Initial GitHub export

This commit is contained in:
Emilia Kasper
2016-10-14 15:58:23 +02:00
committed by Thai Duong
parent c662a0ac90
commit f7ecb0dfad
41 changed files with 8110 additions and 1 deletions
@@ -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());
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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);
}
}
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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 {}
@@ -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
*
* <pre>{@code
* Random rand = new Random();
* rand.setSeed(seed);
* return new BigInteger(k, rand);
* }</pre>
*
* where k is max(64, x.BitLength());
*
* <p>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");
}
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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;
/**
* <p>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.
*
* <p>To exclude certain tests, a runner class should be annotated with {@code @Provider} which
* indicates the target provider. Test exclusion is defined as follows:
* <ul>@Fast test runners skip @SlowTest test functions.
* <ul>@Presubmit test runners skip @NoPresubmitTest test functions.
* <ul>All test runners skip @ExcludedTest test functions.
*
* @author thaidn@google.com (Thai Duong)
*/
public class WycheproofRunner extends Suite {
/** List of supported providers. */
public enum ProviderType {
BOUNCY_CASTLE,
CONSCRYPT,
OPENJDK,
SPONGY_CASTLE,
}
// Annotations for test runners.
/**
* Annotation to specify the target provider of a test runner.
*
* <p>Usage: @Provider(ProviderType.BOUNCY_CASTLE)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Provider {
ProviderType value();
}
/**
* Annotation to specify presubmit test runners that exclude {@code @NoPresubmitTets} tests.
*
* <p>Usage: @Presubmit(ProviderType.BOUNCY_CASTLE)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Presubmit {}
/**
* Annotation to specify fast test runners that exclude {@code @SlowTest} tests.
*
* <p>Usage: @Fast
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Fast {}
// Annotations for test functions
/**
* Tests that take too much time to run, should be excluded from TAP and wildcard target patterns
* like:..., :*, or :all.
*
* <p>Usage: @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ...})
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SlowTest {
ProviderType[] providers();
}
/**
* Tests that should be excluded from presubmit checks on specific providers.
*
* <p>Usage: @NoPresubmitTest(
* providers = {ProviderType.BOUNCY_CASTLE, ...},
* bugs = {"b/123456789"}
* )
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface NoPresubmitTest {
/** List of providers that this test method should not run as presubmit check. */
ProviderType[] providers();
/** List of blocking bugs (and comments). */
String[] bugs();
}
/**
* Annotation to specify test functions that should be excluded on specific providers.
*
* <p>Usage: @ExcludedTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.OPENJDK})
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ExcludedTest {
ProviderType[] providers();
String comment();
}
/**
* Custom filter to exclude certain test functions.
*
*/
public static class ExcludeTestFilter extends Filter {
Class<?> runnerClass;
Provider targetProvider;
Fast fast;
Presubmit presubmit;
public ExcludeTestFilter(Class<?> runnerClass) {
this.runnerClass = runnerClass;
this.targetProvider = runnerClass.getAnnotation(Provider.class);
this.fast = runnerClass.getAnnotation(Fast.class);
this.presubmit = runnerClass.getAnnotation(Presubmit.class);
}
@Override
public String describe() {
return "exclude certain tests on specific providers";
}
@Override
public boolean shouldRun(Description description) {
return isOkayToRunTest(description);
}
private boolean isOkayToRunTest(Description description) {
if (targetProvider == null) {
// Run all test functions if the test runner is not annotated with {@code @Provider}.
return true;
}
// Skip @ExcludedTest tests
ExcludedTest excludedTest = description.getAnnotation(ExcludedTest.class);
if (excludedTest != null
&& Arrays.asList(excludedTest.providers()).contains(targetProvider.value())) {
return false;
}
// If the runner class is annotated with @Presubmit, skip non-presubmit tests
if (presubmit != null) {
NoPresubmitTest ignoreOn = description.getAnnotation(NoPresubmitTest.class);
if (ignoreOn != null
&& Arrays.asList(ignoreOn.providers()).contains(targetProvider.value())) {
return false;
}
}
// If the runner class is annotated with @Fast, skip slow tests
if (fast != null) {
SlowTest ignoreOn = description.getAnnotation(SlowTest.class);
if (ignoreOn != null
&& Arrays.asList(ignoreOn.providers()).contains(targetProvider.value())) {
return false;
}
}
// run everything else
return true;
}
}
/** Required constructor: called by JUnit reflectively. */
public WycheproofRunner(Class<?> runnerClass, RunnerBuilder builder) throws InitializationError {
super(runnerClass, builder);
addFilter(new ExcludeTestFilter(runnerClass));
}
private void addFilter(Filter filter) {
try {
filter(filter);
} catch (NoTestsRemainException ex) {
System.out.println("No tests remain exception: " + ex);
}
}
}
@@ -0,0 +1,268 @@
/**
* @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.
*/
// TODO(bleichen):
// - So far only 16 byte tags are tested.
// Tested providers:
// BC : ok
// BC uses a 64-bit default for tags. This is not such a big
// problem as with AES-GCM, since the tag gives 64 bit strength.
package com.google.security.wycheproof;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import junit.framework.TestCase;
/** AES-EAX tests */
public class AesEaxTest extends TestCase {
/** Test vectors */
public static class EaxTestVector {
final byte[] pt;
final byte[] aad;
final byte[] ct;
final String ptHex;
final String ctHex;
final GCMParameterSpec parameters;
final SecretKeySpec key;
public EaxTestVector(
String message, String keyMaterial, String nonce, String aad, String ciphertext) {
this.ptHex = message;
this.pt = TestUtil.hexToBytes(message);
this.aad = TestUtil.hexToBytes(aad);
this.ct = TestUtil.hexToBytes(ciphertext);
this.ctHex = ciphertext;
// Ugly hack from
// https://github.com/bcgit/bc-java/blob/master/prov/src/test/java/org/bouncycastle/jce/provider/test/AEADTest.java
// Apparently, one way to specify the tag length is to use GCMParameterSpec.
// BouncyCastle is using a 64-bit tag by default.
// So far all test vectors use a 128 bit tag.
this.parameters = new GCMParameterSpec(128, TestUtil.hexToBytes(nonce));
this.key = new SecretKeySpec(TestUtil.hexToBytes(keyMaterial), "AES");
}
};
private static final EaxTestVector[] EAX_TEST_VECTOR = {
// Test vectors from
// http://csrc.nist.gov/groups/ST/toolkit/BCM/modes_development.html
// TODO(bleichen): Check if we can include test cases from NIST and
// republish.
new EaxTestVector(
"",
"233952dee4d5ed5f9b9c6d6ff80ff478",
"62ec67f9c3a4a407fcb2a8c49031a8b3",
"6bfb914fd07eae6b",
"e037830e8389f27b025a2d6527e79d01"),
new EaxTestVector(
"f7fb",
"91945d3f4dcbee0bf45ef52255f095a4",
"becaf043b0a23d843194ba972c66debd",
"fa3bfd4806eb53fa",
"19dd5c4c9331049d0bdab0277408f67967e5"),
new EaxTestVector(
"1a47cb4933",
"01f74ad64077f2e704c0f60ada3dd523",
"70c3db4f0d26368400a10ed05d2bff5e",
"234a3463c1264ac6",
"d851d5bae03a59f238a23e39199dc9266626c40f80"),
new EaxTestVector(
"481c9e39b1",
"d07cf6cbb7f313bdde66b727afd3c5e8",
"8408dfff3c1a2b1292dc199e46b7d617",
"33cce2eabff5a79d",
"632a9d131ad4c168a4225d8e1ff755939974a7bede"),
new EaxTestVector(
"40d0c07da5e4",
"35b6d0580005bbc12b0587124557d2c2",
"fdb6b06676eedc5c61d74276e1f8e816",
"aeb96eaebe2970e9",
"071dfe16c675cb0677e536f73afe6a14b74ee49844dd"),
new EaxTestVector(
"4de3b35c3fc039245bd1fb7d",
"bd8e6e11475e60b268784c38c62feb22",
"6eac5c93072d8e8513f750935e46da1b",
"d4482d1ca78dce0f",
"835bb4f15d743e350e728414abb8644fd6ccb86947c5e10590210a4f"),
new EaxTestVector(
"8b0a79306c9ce7ed99dae4f87f8dd61636",
"7c77d6e813bed5ac98baa417477a2e7d",
"1a8c98dcd73d38393b2bf1569deefc19",
"65d2017990d62528",
"02083e3979da014812f59f11d52630da30137327d10649b0aa6e1c181db617d7" + "f2"),
new EaxTestVector(
"1bda122bce8a8dbaf1877d962b8592dd2d56",
"5fff20cafab119ca2fc73549e20f5b0d",
"dde59b97d722156d4d9aff2bc7559826",
"54b9f04e6a09189a",
"2ec47b2c4954a489afc7ba4897edcdae8cc33b60450599bd02c96382902aef7f" + "832a"),
new EaxTestVector(
"6cf36720872b8513f6eab1a8a44438d5ef11",
"a4a4782bcffd3ec5e7ef6d8c34a56123",
"b781fcf2f75fa5a8de97a9ca48e522ec",
"899a175897561d7e",
"0de18fd0fdd91e7af19f1d8ee8733938b1e8e7f6d2231618102fdb7fe55ff199" + "1700"),
new EaxTestVector(
"ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7",
"8395fcf1e95bebd697bd010bc766aac3",
"22e7add93cfc6393c57ec0b3c17d6b44",
"126735fcc320d25a",
"cb8920f87a6c75cff39627b56e3ed197c552d295a7cfc46afc253b4652b1af37" + "95b124ab6e"),
// The tests are self generated.
//
// Some test vectors for counter overflow:
// Initial counter value == 2^128-1
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111",
"000102030405060708090a0b0c0d0e0f",
"3c8cc2970a008f75cc5beae2847258c2",
"",
"3c441f32ce07822364d7a2990e50bb13d7b02a26969e4a937e5e9073b0d9c968"
+ "db90bdb3da3d00afd0fc6a83551da95e"),
// counter value overflows at 64-bit boundary
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111",
"000102030405060708090a0b0c0d0e0f",
"aef03d00598494e9fb03cd7d8b590866",
"",
"d19ac59849026a91aa1b9aec29b11a202a4d739fd86c28e3ae3d588ea21d70c6"
+ "c30f6cd9202074ed6e2a2a360eac8c47"),
// no counter overflow, but the 64 most significant bits are set.
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111",
"000102030405060708090a0b0c0d0e0f",
"55d12511c696a80d0514d1ffba49cada",
"",
"2108558ac4b2c2d5cc66cea51d6210e046177a67631cd2dd8f09469733acb517"
+ "fc355e87a267be3ae3e44c0bf3f99b2b"),
// counter value overflows at 32-bit boundary
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111",
"000102030405060708090a0b0c0d0e0f",
"79422ddd91c4eee2deaef1f968305304",
"",
"4d2c1524ca4baa4eefcce6b91b227ee83abaff8105dcafa2ab191f5df2575035"
+ "e2c865ce2d7abdac024c6f991a848390"),
// no counter overflow, but bits 32-64 and 96-128 are set.
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111",
"000102030405060708090a0b0c0d0e0f",
"0af5aa7a7676e28306306bcd9bf2003a",
"",
"8eb01e62185d782eb9287a341a6862ac5257d6f9adc99ee0a24d9c22b3e9b38a"
+ "39c339bc8a74c75e2c65c6119544d61e"),
// no counter overflow, lower 64 bits are 2^63-1
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111",
"000102030405060708090a0b0c0d0e0f",
"af5a03ae7edd73471bdcdfac5e194a60",
"",
"94c5d2aca6dbbce8c24513a25e095c0e54a942860d327a222a815cc713b163b4"
+ "f50b30304e45c9d411e8df4508a98612"),
// counter overflow between block 2 and block 3.
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111"
+ "2222222222222222222222222222222233333333333333333333333333333333",
"000102030405060708090a0b0c0d0e0f",
"b37087680f0edd5a52228b8c7aaea664",
"",
"3bb6173e3772d4b62eef37f9ef0781f360b6c74be3bf6b371067bc1b090d9d66"
+ "22a1fbec6ac471b3349cd4277a101d40890fbf27dfdcd0b4e3781f9806daabb6"
+ "a0498745e59999ddc32d5b140241124e"),
// no counter overflow, the lower 64 bits are 2^63-4.
new EaxTestVector(
"0000000000000000000000000000000011111111111111111111111111111111"
+ "2222222222222222222222222222222233333333333333333333333333333333"
+ "44444444444444444444444444444444",
"000102030405060708090a0b0c0d0e0f",
"4f802da62a384555a19bc2b382eb25af",
"",
"e9b0bb8857818ce3201c3690d21daa7f264fb8ee93cc7a4674ea2fc32bf182fb"
+ "2a7e8ad51507ad4f31cefc2356fe7936a7f6e19f95e88fdbf17620916d3a6f3d"
+ "01fc17d358672f777fd4099246e436e167910be744b8315ae0eb6124590c5d8b"),
// 192-bit keys
new EaxTestVector(
"",
"03dd258601c1d4872a52b27892db0356911b2df1436dc7f4",
"723cb2022102113018dcd2d204022114",
"",
"c472b1c6c22b4f2b7e02409499aa2ade"),
new EaxTestVector(
"abcdef",
"03dd258601c1d4872a52b27892db0356911b2df1436dc7f4",
"025f3d2286c143976412022102696708231208",
"8917328de211",
"520f4f2cf1b893ae3ba8ecbac3a08ea57de2cd"),
new EaxTestVector(
"1111111111111111111111111111111122222222222222222222222222222222",
"0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
"000102030405060708090a0b0c0d0e0f1a1b1c1d",
"77922d34e452e0a40962873d22901dd22ad1c303",
"5917879b9fa85f4007b7bd0cd46f067d5a7bf287f19dfcc5475c95a4acce520a"
+ "4c5df804bc091a3b5d6c838b7e494571"),
// 256-bit keys
new EaxTestVector(
"",
"0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
"696708231208",
"",
"7c8f86f837a4f72c574678d92f637f07"),
new EaxTestVector(
"abcdef",
"0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
"696708231208",
"8917328de211",
"12486c87bf9a7f22fa65a9493ec0f57f8070f5"),
new EaxTestVector(
"1111111111111111111111111111111122222222222222222222222222222222",
"0172acf299142c001d0c231287c1182784554ca3a21908276ac2c92af1294612",
"000102030405060708090a0b0c0d0e0f1a1b1c1d",
"92d3e42e0409273291d2dc034450",
"5917879b9fa85f4007b7bd0cd46f067d5a7bf287f19dfcc5475c95a4acce520a"
+ "e632946e4999be20159977431bef0454"),
};
public void testEax() throws Exception {
for (EaxTestVector test : EAX_TEST_VECTOR) {
Cipher cipher = Cipher.getInstance("AES/EAX/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
cipher.updateAAD(test.aad);
byte[] ct = cipher.doFinal(test.pt);
assertEquals(test.ctHex, TestUtil.bytesToHex(ct));
}
}
public void testLateUpdateAAD() throws Exception {
for (EaxTestVector test : EAX_TEST_VECTOR) {
Cipher cipher = Cipher.getInstance("AES/EAX/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
byte[] c0 = cipher.update(test.pt);
try {
cipher.updateAAD(test.aad);
} catch (java.lang.IllegalStateException ex) {
// Typically one should pass the AAD in first.
// Hence it is OK to get this exception.
// For example, this is the behaviour of SUNJce.
continue;
}
byte[] c1 = cipher.doFinal();
String result = TestUtil.bytesToHex(c0) + TestUtil.bytesToHex(c1);
assertEquals(test.ctHex, result);
}
}
}
@@ -0,0 +1,405 @@
/**
* @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.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import junit.framework.TestCase;
// TODO(bleichen):
// - For EAX I was able to derive some special cases by inverting OMAC.
// Not sure if that is possible here.
// - Gcm used to skip the tag verification in BouncyCastle when using ByteBuffers.
// test this.
// - Other Bytebuffer tests: Buffers with offset, Readonly buffers
// - The SUNJce provider requires tags that are at least 96 bits long.
// It would make sense to require this for all providers and add a test.
// - conscrypt only allows 12 byte IVs.
/**
* Testing AES-GCM
*
* <p>Other tests using AES-GCM are: CipherInputStreamTest.java CipherOuputStreamTest.java
*/
public class AesGcmTest extends TestCase {
/** Test vectors */
public static class GcmTestVector {
final byte[] pt;
final byte[] aad;
final byte[] ct;
final String ptHex;
final String ctHex;
final GCMParameterSpec parameters;
final SecretKeySpec key;
public GcmTestVector(
String message,
String keyMaterial,
String nonce,
String aad,
String ciphertext,
String tag) {
this.ptHex = message;
this.pt = TestUtil.hexToBytes(message);
this.aad = TestUtil.hexToBytes(aad);
this.ct = TestUtil.hexToBytes(ciphertext + tag);
this.ctHex = ciphertext + tag;
int tagLength = 4 * tag.length();
this.parameters = new GCMParameterSpec(tagLength, TestUtil.hexToBytes(nonce));
this.key = new SecretKeySpec(TestUtil.hexToBytes(keyMaterial), "AES");
}
};
// default, used for BouncyCastle
private static final GcmTestVector[] DEFAULT_GCM_TEST_VECTORS = {
new GcmTestVector(
"001d0c231287c1182784554ca3a21908",
"5b9604fe14eadba931b0ccf34843dab9",
"028318abc1824029138141a2",
"",
"26073cc1d851beff176384dc9896d5ff",
"0a3ea7a5487cb5f7d70fb6c58d038554"),
new GcmTestVector(
"001d0c231287c1182784554ca3a21908",
"5b9604fe14eadba931b0ccf34843dab9",
"921d2507fa8007b7bd067d34",
"00112233445566778899aabbccddeeff",
"49d8b9783e911913d87094d1f63cc765",
"1e348ba07cca2cf04c618cb4"),
new GcmTestVector(
"2035af313d1346ab00154fea78322105",
"aa023d0478dcb2b2312498293d9a9129",
"0432bc49ac34412081288127",
"aac39231129872a2",
"eea945f3d0f98cc0fbab472a0cf24e87",
"4bb9b4812519dadf9e1232016d068133"),
new GcmTestVector(
"2035af313d1346ab00154fea78322105",
"aa023d0478dcb2b2312498293d9a9129",
"0432bc49ac344120",
"aac39231129872a2",
"64c36bb3b732034e3a7d04efc5197785",
"b7d0dd70b00d65b97cfd080ff4b819d1"),
};
// Conscrypt doesn't support 8-byte nonces
private static final GcmTestVector[] OPENSSL_PROVIDER_GCM_TEST_VECTORS = {
new GcmTestVector(
"001d0c231287c1182784554ca3a21908",
"5b9604fe14eadba931b0ccf34843dab9",
"028318abc1824029138141a2",
"",
"26073cc1d851beff176384dc9896d5ff",
"0a3ea7a5487cb5f7d70fb6c58d038554"),
new GcmTestVector(
"001d0c231287c1182784554ca3a21908",
"5b9604fe14eadba931b0ccf34843dab9",
"921d2507fa8007b7bd067d34",
"00112233445566778899aabbccddeeff",
"49d8b9783e911913d87094d1f63cc765",
"1e348ba07cca2cf0"),
new GcmTestVector(
"2035af313d1346ab00154fea78322105",
"aa023d0478dcb2b2312498293d9a9129",
"0432bc49ac34412081288127",
"aac39231129872a2",
"eea945f3d0f98cc0fbab472a0cf24e87",
"4bb9b4812519dadf9e1232016d068133"),
};
// SunJCE doesn't support 8-byte tags
private static final GcmTestVector[] SUNJCE_PROVIDER_GCM_TEST_VECTORS = {
new GcmTestVector(
"001d0c231287c1182784554ca3a21908",
"5b9604fe14eadba931b0ccf34843dab9",
"028318abc1824029138141a2",
"",
"26073cc1d851beff176384dc9896d5ff",
"0a3ea7a5487cb5f7d70fb6c58d038554"),
new GcmTestVector(
"2035af313d1346ab00154fea78322105",
"aa023d0478dcb2b2312498293d9a9129",
"0432bc49ac34412081288127",
"aac39231129872a2",
"eea945f3d0f98cc0fbab472a0cf24e87",
"4bb9b4812519dadf9e1232016d068133"),
new GcmTestVector(
"2035af313d1346ab00154fea78322105",
"aa023d0478dcb2b2312498293d9a9129",
"0432bc49ac344120",
"aac39231129872a2",
"64c36bb3b732034e3a7d04efc5197785",
"b7d0dd70b00d65b97cfd080ff4b819d1"),
};
private GcmTestVector[] getTestVectors() {
GcmTestVector[] gcmTestVectors = DEFAULT_GCM_TEST_VECTORS;
if (Security.getProvider("AndroidOpenSSL") != null) {
gcmTestVectors = OPENSSL_PROVIDER_GCM_TEST_VECTORS;
} else if (Security.getProvider("SunJCE") != null) {
gcmTestVectors = SUNJCE_PROVIDER_GCM_TEST_VECTORS;
}
return gcmTestVectors;
}
public void testVectors() throws Exception {
GcmTestVector[] gcmTestVectors = getTestVectors();
for (GcmTestVector test : gcmTestVectors) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
cipher.updateAAD(test.aad);
byte[] ct = cipher.doFinal(test.pt);
assertEquals(test.ctHex, TestUtil.bytesToHex(ct));
}
}
/**
* Typically one should always call updateAAD before any call to update. This test checks what
* happens if the order is reversed. The test expects that a correct implementation either
* computes the tag correctly or throws an exception.
*
* <p>For example, OpenJdk did compute incorrect tags in this case. The bug has been fixed in
* http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/89c06ca1e6cc
*
* <p>For example BouncyCastle computes correct tags if the calls are reversed, SunJCE and OpenJdk
* now throw exceptions.
*/
public void testLateUpdateAAD() throws Exception {
GcmTestVector[] gcmTestVectors = getTestVectors();
for (GcmTestVector test : gcmTestVectors) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
byte[] c0 = cipher.update(test.pt);
try {
cipher.updateAAD(test.aad);
} catch (java.lang.IllegalStateException ex) {
// Throwing an exception is valid behaviour.
continue;
}
byte[] c1 = cipher.doFinal();
String result = TestUtil.bytesToHex(c0) + TestUtil.bytesToHex(c1);
assertEquals(test.ctHex, result);
}
}
/** Encryption with ByteBuffers. */
public void testByteBuffer() throws Exception {
GcmTestVector[] gcmTestVectors = getTestVectors();
for (GcmTestVector test : gcmTestVectors) {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt);
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
cipher.doFinal(ptBuffer, ctBuffer);
assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
// Decryption
ctBuffer.flip();
cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
outputSize = cipher.getOutputSize(test.ct.length);
ByteBuffer decrypted = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
cipher.doFinal(ctBuffer, decrypted);
assertEquals(test.ptHex, TestUtil.byteBufferToHex(decrypted));
}
}
/** Encryption with ByteBuffers should be copy-safe. */
public void testByteBufferAlias() throws Exception {
GcmTestVector[] gcmTestVectors = getTestVectors();
for (GcmTestVector test : gcmTestVectors) {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
byte[] backingArray = new byte[outputSize];
ByteBuffer ptBuffer = ByteBuffer.wrap(backingArray);
ptBuffer.put(test.pt);
ptBuffer.flip();
ByteBuffer ctBuffer = ByteBuffer.wrap(backingArray);
cipher.updateAAD(test.aad);
cipher.doFinal(ptBuffer, ctBuffer);
assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
// Decryption
ByteBuffer decrypted = ByteBuffer.wrap(backingArray);
ctBuffer.flip();
cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
cipher.updateAAD(test.aad);
cipher.doFinal(ctBuffer, decrypted);
assertEquals(test.ptHex, TestUtil.byteBufferToHex(decrypted));
}
}
public void testReadOnlyByteBuffer() throws Exception {
GcmTestVector[] gcmTestVectors = getTestVectors();
for (GcmTestVector test : gcmTestVectors) {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt).asReadOnlyBuffer();
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
int outputSize = cipher.getOutputSize(test.pt.length);
ByteBuffer ctBuffer = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
cipher.doFinal(ptBuffer, ctBuffer);
assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
// Decryption
ctBuffer.flip();
ctBuffer = ctBuffer.asReadOnlyBuffer();
cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
outputSize = cipher.getOutputSize(test.ct.length);
ByteBuffer decrypted = ByteBuffer.allocate(outputSize);
cipher.updateAAD(test.aad);
cipher.doFinal(ctBuffer, decrypted);
assertEquals(test.ptHex, TestUtil.byteBufferToHex(decrypted));
}
}
/**
* If a ByteBuffer is backed by an array and not readonly, then it is possible to access the data
* through the .array() method. An implementation using this possiblity must ensure that it
* considers the offset.
*/
public void testByteBufferWithOffset() throws Exception {
GcmTestVector[] gcmTestVectors = getTestVectors();
for (GcmTestVector test : gcmTestVectors) {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
ByteBuffer ptBuffer = ByteBuffer.wrap(new byte[test.pt.length + 50]);
ptBuffer.position(5);
ptBuffer = ptBuffer.slice();
ptBuffer.put(test.pt);
ptBuffer.flip();
ByteBuffer ctBuffer = ByteBuffer.wrap(new byte[test.ct.length + 50]);
ctBuffer.position(8);
ctBuffer = ctBuffer.slice();
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
cipher.updateAAD(test.aad);
cipher.doFinal(ptBuffer, ctBuffer);
assertEquals(test.ctHex, TestUtil.byteBufferToHex(ctBuffer));
ctBuffer.flip();
// Decryption
ByteBuffer decBuffer = ByteBuffer.wrap(new byte[test.pt.length + 50]);
decBuffer.position(6);
decBuffer = decBuffer.slice();
cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
cipher.updateAAD(test.aad);
cipher.doFinal(ctBuffer, decBuffer);
assertEquals(test.ptHex, TestUtil.byteBufferToHex(decBuffer));
}
}
public void testByteBufferTooShort() throws Exception {
GcmTestVector[] gcmTestVectors = getTestVectors();
for (GcmTestVector test : gcmTestVectors) {
// Encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
ByteBuffer ptBuffer = ByteBuffer.wrap(test.pt);
ByteBuffer ctBuffer = ByteBuffer.allocate(test.ct.length - 1);
cipher.init(Cipher.ENCRYPT_MODE, test.key, test.parameters);
cipher.updateAAD(test.aad);
try {
cipher.doFinal(ptBuffer, ctBuffer);
fail("This should not work");
} catch (ShortBufferException ex) {
// expected
}
// Decryption
ctBuffer = ByteBuffer.wrap(test.ct);
ByteBuffer decrypted = ByteBuffer.allocate(test.pt.length - 1);
cipher.init(Cipher.DECRYPT_MODE, test.key, test.parameters);
cipher.updateAAD(test.aad);
try {
cipher.doFinal(ctBuffer, decrypted);
fail("This should not work");
} catch (ShortBufferException ex) {
// expected
}
}
}
/**
* The default authentication tag size should be 128-bit by default for the following reasons:
* <br>
* (1) Security: Ferguson, N., Authentication Weaknesses in GCM, Natl. Inst. Stand. Technol. [Web
* page], http://www.csrc.nist.gov/groups/ST/toolkit/BCM/documents/comments/
* CWC-GCM/Ferguson2.pdf, May 20, 2005. This paper points out that a n-bit tag has lower strength
* than expected. <br>
* (2) Compatibility: Assume an implementer tests some code using one provider than switches to
* another provider. Such a switch should ideally not lower the security. <br>
* Conscrypt used to have only 12-byte authentication tag (b/26186727).
*/
public void testDefaultTagSizeIvParameterSpec() throws Exception {
byte[] counter = new byte[12];
byte[] input = new byte[16];
byte[] key = new byte[16];
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
try {
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(counter));
} catch (InvalidAlgorithmParameterException ex) {
// OpenJDK8 does not support IvParameterSpec for GCM.
System.out.println(ex);
return;
}
byte[] output = cipher.doFinal(input);
assertEquals(input.length + 16, output.length);
}
/**
* The default authentication tag size should be 128-bit by default for the following reasons:
* <br>
* (1) Security: Ferguson, N., Authentication Weaknesses in GCM, Natl. Inst. Stand. Technol. [Web
* page], http://www.csrc.nist.gov/groups/ST/toolkit/BCM/documents/comments/
* CWC-GCM/Ferguson2.pdf, May 20, 2005. This paper points out that a n-bit tag has lower strength
* than expected. <br>
* (2) Compatibility: Assume an implementer tests some code using one provider than switches to
* another provider. Such a switch should ideally not lower the security. <br>
* BouncyCastle used to have only 12-byte authentication tag (b/26186727).
*/
public void testDefaultTagSizeAlgorithmParameterGenerator() throws Exception {
byte[] input = new byte[10];
byte[] key = new byte[16];
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
try {
AlgorithmParameterGenerator.getInstance("GCM");
} catch (NoSuchAlgorithmException ex) {
// Conscrypt does not support AlgorithmParameterGenerator for GCM.
System.out.println(ex);
return;
}
AlgorithmParameters param = AlgorithmParameterGenerator.getInstance("GCM").generateParameters();
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), param);
byte[] output = cipher.doFinal(input);
assertEquals(input.length + 16, output.length);
}
}
@@ -0,0 +1,45 @@
/**
* @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.security.Provider;
import java.security.Security;
import java.util.TreeSet;
import junit.framework.TestCase;
/** Not a true test: reports information about the provider. */
public class BasicTest extends TestCase {
/** List all algorithms known to the security manager. */
public void testListAllAlgorithms() {
for (Provider p : Security.getProviders()) {
System.out.println();
System.out.println("Provider:" + p.getName());
// Using a TreeSet here, because the elements are sorted.
TreeSet<String> list = new TreeSet<String>();
for (Object key : p.keySet()) {
list.add((String) key);
}
for (String algorithm : list) {
if (algorithm.startsWith("Alg.Alias.")) {
continue;
}
System.out.println(algorithm);
}
}
}
}
@@ -0,0 +1,461 @@
/**
* @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 junit.framework.TestCase;
/**
* Test BigInteger class.
*
* <p>This unit tests focuses on checking security relevant properties.
*/
public class BigIntegerTest extends TestCase {
public static final BigInteger[] NONPRIMES =
new BigInteger[] {
// small non prime integers
new BigInteger("-1"),
new BigInteger("0"),
new BigInteger("1"),
// If p is prime then the Mersenne number 2^p-1 is pseudoprime for base 2.
new BigInteger("147573952589676412927"),
new BigInteger("2361183241434822606847"),
// pseudoprime squares derived from Wiefrich primes
new BigInteger("1194649"),
new BigInteger("12327121"),
// G. Jaeschke: "On strong pseudoprimes to several bases", Math o. comp. v.61, p 915-926
new BigInteger("2152302898747"),
new BigInteger("3474749660383"),
new BigInteger("341550071728321"),
new BigInteger("41234316135705689041"),
new BigInteger("1553360566073143205541002401"),
new BigInteger("56897193526942024370326972321"),
// A list of strong pseudoprimes to 12 or more bases from
// https://arxiv.org/pdf/1509.00864v1.pdf
new BigInteger("360681321802296925566181"),
new BigInteger("164280218643672633986221"),
new BigInteger("318665857834031151167461"),
new BigInteger("7395010240794120709381"),
new BigInteger("164280218643672633986221"),
new BigInteger("318665857834031151167461"),
new BigInteger("2995741773170734841812261"),
new BigInteger("667636712015520329618581"),
new BigInteger("3317044064679887385961981"),
new BigInteger("3110269097300703345712981"),
new BigInteger("552727880697763694556181"),
new BigInteger("360681321802296925566181"),
new BigInteger("7395010240794120709381"),
new BigInteger("3404730287403079539471001"),
new BigInteger("164280218643672633986221"),
// Richarg G.E. Pinch, "Some primality testing algorithms"
// Some composites that passed Maple V's primality test.
new BigInteger("10710604680091"),
new BigInteger("4498414682539051"),
new BigInteger("6830509209595831"),
// Composites that passed the primality test of Mathematica 2.0
new BigInteger("38200901201"),
new BigInteger("6646915915638769"),
// Composites that passed Axioms primality tests
new BigInteger("168790877523676911809192454171451"),
new BigInteger("68528663395046912244223605902738356719751082784386681071"),
// A composite q that was acceptied by Gnu Crypto. p = 2*q + 1 is prime and could have been
// used to break the SRP with that library.
// http://www.iacr.org/archive/pkc2005/33860010/33860010.pdf
new BigInteger(
"2338274894573145273314679073561004052325493799717332496500873981"
+ "9154269566267911565762670147721173495706686483597956042863296855"
+ "8985491020031718032728786934761830612407539788738389834804112831"
+ "0484933712924414264511799715503596253054638290097305254378560604"
+ "3457282155730383806702845548017315217454390994052035233808454053"
+ "2209678251"),
// I. Damgard, P. Landrock, and C. Pomerance. "Average case error estimates for the strong
// probable prime test." Math. of Comp. v.61 (203), pp. 177-194.
//
// This paper gives bounds for the number of bases necessary to distinguish composites from
// primes assuming that the tested integer has been chosen at random.
//
// The result is sometimes misinterpreted and used for pseudo primality tests. There the
// assumption of the paper may not be valid, especially if the integer to test has been
// chosen by a potentially malicious party. The following pseudoprimes are 1024 to 1280 bits
// long, pass the MR test for about 1/4 of all bases. They may expose pseudo primality tests
// that misinterpret the paper above.
new BigInteger(
"1730626114143993906582329178627391355248485443639984363030847275"
+ "1308542667309368405802823431259718338553667079600118481458180717"
+ "8685660312964257923307841168376622412972295432300191118906455596"
+ "0636099366430317210651098229261736987868487865820945209431391380"
+ "09108180649097618810676094425505547347369635059151651"),
new BigInteger(
"1360998858923994584770803056737393786894832450662215840614559215"
+ "7078401469699701619693552331616875038702785662417391573713804038"
+ "4334162971247398689854706029275431407028615888533012918610480990"
+ "0223861487963796923928503972465761214360888693859314270808955367"
+ "40913457414488449790876563256100025424908640036566991"),
new BigInteger(
"3166883756083864374213797577792765404121225450334428749136082272"
+ "6277047033553982548405648549530365358167591776542577633638251648"
+ "4708794514891794859629545011811469601460428778510574606216627610"
+ "9305946545256861710197652701722202600572822026157108510694466031"
+ "21873496655525294839125742517721479483987924741221051"),
new BigInteger(
"1867856940026786421328012256561867196437042470176831233408635728"
+ "4012048133274069029642553787088950310027377534718962029124718226"
+ "6051117402306961193255486702389001315623336948708913938663766675"
+ "8226042898352219886123870222547007370332879734207273564946511954"
+ "31833673259400609717994958747847898007198993092012403"),
new BigInteger(
"1796390661263009677994016718416108866609292079197277387452323006"
+ "0275054640418696223480642324316099214952402651731083265854610369"
+ "8224730515713772933976457906751697355710699183284927973990745341"
+ "2311585789546147810071014069499060003398982340466066800822746698"
+ "64309065127941774208780103317444828873858305613764441"),
new BigInteger(
"1971945240855615239359385779848543278459852521629467703761094672"
+ "8118959477624582999696057042356627216821194209090396598966531204"
+ "6718418693934025583647341695134065566474352554207810854787929284"
+ "0150420997586371167811999782663434687606795518115913678131471778"
+ "75984898571603525952885934025286780854976730638309011"),
new BigInteger(
"3150008132483461686934076250569912489352161839369648385736587811"
+ "5997183822673267428826594197361084397177321281419482762875475084"
+ "9549588421903702315436565970387119142993552663715551586581960248"
+ "0385985798377103010348982470471826679560834315129605222126122792"
+ "66245495948831504762364224662571600318327270033084451"),
new BigInteger(
"1708946102366142320715649564941267111465045510329061281476212740"
+ "3257341007679575909346478379354045686824680545379443269343860874"
+ "7656833753674500442989626468892341565281803639470271121897646438"
+ "0297951614184327979794615696929197488480659590917557764806142256"
+ "64177795195470929762281195447906351417368682849843661"),
new BigInteger(
"3440003701993474165051634746793659123122285886429390887874425798"
+ "0539628797086399700050400512078053335053587477375429177907276765"
+ "7299212000552180980839328379536622696237474649639004862671352175"
+ "9289352494669383679530748723706821659664185661303953233767365167"
+ "67872755699135674189217223109386132423577475778316621"),
new BigInteger(
"1384489093437226718803143517408309162781203263729355872818628349"
+ "4469526441585078582037579393159945688413133085030944516305313234"
+ "8118439725196722488178936032989162127096990828542718648126854836"
+ "3215014994571003679167792328172868632219526006267874696849394364"
+ "51238457213158274397103569820623680840515654121967511"),
new BigInteger(
"3164393868232068713466361644489248900506521258778648162638744470"
+ "1911965299134147189251276735683301303659631352068168884603764242"
+ "2058303711027020977731971469313828021385806157441077657252831199"
+ "5151267291454080409585783805054468065763411635886980943812129069"
+ "12979884469786023782783106107762632814558326808787771"),
new BigInteger(
"3429610981008641614862240834440649965306153336087134811684334214"
+ "2781784784880823158748073620472850986640780368357758806487624898"
+ "6627917970721407574366482474956464008840562218539437088991213443"
+ "6865812444686702307687466249240837612849694711488568460832793683"
+ "75653516879275492605255161494494045951397742913942521"),
new BigInteger(
"1452625971469501984029833170297844688666257429198467445330023676"
+ "9656278238192507513913993052034672663086092503841752084104847874"
+ "8173408690100803386628315407260460724324957380860416531476612359"
+ "3906755149555321240901275978836270398698785709389076413509994529"
+ "42901485886289548101644664410043634050840333618736241"),
new BigInteger(
"1038759703926769528247935492263828939187707228977771863002037516"
+ "6447956205097712397228992931571755867770661683705025240420111189"
+ "2868394359927108413461144788316226799790655169187714036057483534"
+ "1379449940364129845302840193911613461736295410032863048528135257"
+ "04436628490382188950208123780350213139500089456366841"),
new BigInteger(
"2092626848347087607813788288260128832160456227715887480495928337"
+ "8143090879636401536763351823849725734769339835456348322174433133"
+ "2528919261931329808331753456631473557050588173643619875493912344"
+ "2621229276297788264420214803881217267094948976676445054939538411"
+ "22580436721054077839958796624587867034849970594728503"),
new BigInteger(
"2599619740922490310102276030628575944314398371981276430688469612"
+ "6677200542107317525516057185980658562393307608335402672015071146"
+ "4375869967746325500371685760342898099183114419807958654613613854"
+ "3992594086574371567802232690430810966098771990068625112489903295"
+ "89067604336669355585402887916288037943709029191674911"),
new BigInteger(
"1484944124031033226177904474729672080414277081288126930486713099"
+ "2951571588154552341076434413035940622712601649739964234772603407"
+ "4857469854866669198948655053082186111410005989963123962723450119"
+ "6642285521712848015932226566546835102733706632115364632204156914"
+ "64644614536183219912321808854090915103775109695786903"),
new BigInteger(
"1989518237873611249304118136102198299910749751063921465712157675"
+ "0160983808717982713586255483659294934004326549705203383719900307"
+ "1263871954417468537542759843054899935687365194283002403584007149"
+ "4878371117610681917576307737065411378178051858121032451282900716"
+ "73542006653340382017735899123084476453857081318545991"),
new BigInteger(
"1001516549472529960430483041632117547467775871427023066924341669"
+ "8403875533009883195522874469432253701609651260735835128759135299"
+ "5655554893223580483857764100115214746205606713424344869011314868"
+ "3107942731565140938612794494135227597999675233998980692687287393"
+ "67463341929936509718884001903262839905032784262429503"),
new BigInteger(
"9523120659259647017050060990584944204556454726505878376759616021"
+ "0162649328723702952067039028722189901551617226203049071432575686"
+ "9121080710327716161595367835528315683397536615084723082551568364"
+ "5739952184995573677453019127607472426963971562388390300785220049"
+ "6655144350028488056721467755918814393298596327869403"),
new BigInteger(
"1132692896131390459872218381686704761578367301590229517271338668"
+ "7180351798454882497438382954425835621126393661367213143371283272"
+ "0317909560575328664237540188143415517690966913820407105917871661"
+ "6365405171372246705778112163771743546945868623307467307997875571"
+ "40869529264839386342569691698111927128704157615097153"),
new BigInteger(
"1468478445343635885853097900396288249751127795088868633754583040"
+ "9902362001013473990040942210829761549194134324343879441927807081"
+ "4832779046634885071582835688508933384516245429006116427382617949"
+ "0797131644177507421862332328509904031871287120929769029086074503"
+ "38866991708762791875618755240139448209180903665732503"),
new BigInteger(
"3584128102219288461651881096063603237206550481422480899564693370"
+ "6989198816192527918220789937223699304075118319904981106473056074"
+ "6022073963857677172123650694187762839204698560127083582857191356"
+ "7619601857134928125369766912580367127840531257344393938629885107"
+ "16841734490107828355376447675347185589367615046902903"),
new BigInteger(
"1364132540730201251194341844655148002850736352953819312409033451"
+ "0581806956034928961765696532883678319811153534823893271895441595"
+ "1560405730847235775035340408484490592989244418679611824558459897"
+ "3970103405588145228028549820125837425523682281669049087481368021"
+ "33702260393866732616878693744975284760231993354960641"),
new BigInteger(
"1201213090774136737579735845388953400530787071160074364126728551"
+ "5147303301856817241515212573079940841340044269783294804816431383"
+ "8284868252529547559069691488487393115675459439240223181642866729"
+ "3429931964973711015111163544551414299071832349845971998375812575"
+ "43510797169400923829329952407436122292964382266031253"),
new BigInteger(
"2749611624987217008377958765718501619519235049877079452181305657"
+ "4724564026272242180811435338643866876903591496649439319889570905"
+ "0358277453956447636555409300854018401232502616530331143658908539"
+ "1682266093367017969369633046927346949982338985082398103545735993"
+ "26268702707614772584950389057955691219494031838859791"),
new BigInteger(
"2472982114742145360236684931488791833991329788857529670921519821"
+ "2275589064185672494327017904494686810840150314271250166999768972"
+ "5488277075239138647902134463451436706674384070937644414378922408"
+ "3974240802538174272534726968041801996779685771019246098603577098"
+ "48139330190576017582503777009836399771498662905893541"),
new BigInteger(
"1865347188865809981733701115448160790425846704558108501171803277"
+ "4616363375301457541345495992357828826645510919897778446537615423"
+ "0882378024111971510810465276396395657415178370245114122816237302"
+ "3283933030997110906700611097744954222271394790237582780817507949"
+ "50528224900273599212004329531461848157373189908642761"),
new BigInteger(
"2852220663043188088074403487569592065121097371561337653207919689"
+ "5806125544163953214258963319594971029379263400735515369955250013"
+ "4028759770788754166339078427645792536001991144766729628117371050"
+ "3065276544543379585207323093069812639902415298676791716773723086"
+ "01834079961869281917489638496882679996929360595283091"),
new BigInteger(
"1812266945737014247808099956042081894034544124660090203840602123"
+ "8933795306490611245152382127750687774085253618514158494675518742"
+ "0904863344271961110077635791220319963938065397633608138595169161"
+ "4365952732191284608496816156732317034130054052863296504407952482"
+ "70402413500178325587999299003705988651612697260381081"),
new BigInteger(
"3461478020849089881636057301867459968070516872602987322072552610"
+ "6122696717667098851127207650635960731479969936151065921604956606"
+ "9966154794154897232197433347544538725616640069913605417680979153"
+ "7941663920296351630552463916932109774095427601318332413237900565"
+ "33380330505490643091283956267491266793755039018149751"),
new BigInteger(
"2919979800970068658905539811038971051531482233418344434620488229"
+ "7069955478191515351496193695554391114007400265274653645749899336"
+ "1682279972987736655018586409178146143048864596533190807270958265"
+ "8386345811616055097769189859096393752934393213978617302764485594"
+ "27971296399182413971389773786687947710326691137231821"),
new BigInteger(
"4145154657949019520090421067892641813006171355169512965016842717"
+ "9656056083456770700476740539321891137934371895885040718614132068"
+ "7659642286859932894319946334724710913927915623235424403674960713"
+ "3015105499354740364264523832014989327244648027567866644179973588"
+ "6851400410006028767095438327490143741004842299878541824964849824"
+ "9350463409537126165182086675091928210325509674933575383432172361"
+ "1"),
new BigInteger(
"7263570684005586918409651676342477962666063384721447164820162267"
+ "3637900031379949446961412145104626127789865770334124795558653625"
+ "0265693033953361779942717984970881106667840356057452866357943677"
+ "0299187611159071848712668510417692823114550446719084221850233353"
+ "5448622581084864206413295247972240845959033925761759264503271102"
+ "8711358281311325650083539770515252900036932499310037595977096965"
+ "3"),
new BigInteger(
"3266663369261434628530741133725226939380890029427130078147736465"
+ "2996576096098663002890375510448427552966457154556853852292297530"
+ "3748877081504218804805934729044054195328441392083622877088337833"
+ "3839361634881282676119589334709165541036798092721269225600972531"
+ "5718770210834831734568895865334347621480511738343920340920819445"
+ "8602267925535790135884214787193459118783550610652631217006506945"
+ "3"),
new BigInteger(
"2714275054823322283846947242758076394288969833351667671546539844"
+ "8651643040817257191932781992745878593029648459331742640462067216"
+ "1697889841582474665251728415469605782526629276939159099241968231"
+ "4563946417035619325266947257091436696492494177352417584114484475"
+ "6610785746958696759938071286674788996869751533043564234638049802"
+ "5949514917474176492949501669603402532532836245346872590582496734"
+ "1"),
new BigInteger(
"9266983839147571189339684823228253420616685503762301572754412275"
+ "1127843293258964600702452397526178329259267484695086911638972315"
+ "4961995491900251718105624646921122900256992784437600453557273835"
+ "3861591882136393291951512396743267427648075154617935904316277726"
+ "4493865072538820667287351636308197262473273185496543102226470825"
+ "6662877019047683511136380480413028925833068997034750517865449915"
+ "3"),
new BigInteger(
"6943685859962113005380005918916483733270787990846044283782171250"
+ "1096851232736318325302320935157976786131666696364333532268184395"
+ "8665950723719162662956110077840013184726020313880442980629145593"
+ "2383952066228056762115442513166346145910224582828425403465971492"
+ "7260150227126350939033438077449255619231502836209591891037493966"
+ "9366963730251619187615962926310287121840421140621429191345783703"
+ "1"),
new BigInteger(
"8697498751458522624235585703214358189002281420472600166267178848"
+ "9809876665869248037334395420081653868096056103537493131465377226"
+ "0261527380426559408040456405219848362023445401145511114936506394"
+ "6240472545398288332411818055040869427951279027405975059749360297"
+ "5868667379863439430711990295232153128900808256212596912819669440"
+ "8461633147852596585348243485566178333170181585431955731179108942"
+ "1"),
new BigInteger(
"4252141813347264797276096871298065242070358505647997888003056375"
+ "0053145248543520793105289129514510723624029989029530989695904117"
+ "1040883775014117200916554841688641022136017868157290925811239787"
+ "3664014299809018676076741787758620956387796785085878200748397774"
+ "1000982778291877557074489243525397961477916369196578483491169386"
+ "2005017885694815977695115290403992818456642027646266206320076800"
+ "3"),
new BigInteger(
"3356647398302910967427184201762737607743709740247537918189248572"
+ "1755339542838026890625250818518527348898974773340867800840791470"
+ "3182072707032492007084043715576322632015800128489921814932124611"
+ "2300036417841991332124497348096579076242448857352000771247540736"
+ "1254949324799638105796121388483225300620211599611028678202393567"
+ "8095635541751658983704832859578366318530922805928053806070359946"
+ "1"),
new BigInteger(
"3687125575229624930459923973437509789116885700012081850445193578"
+ "4486423768425089350932846437401841871613673810991112360643320652"
+ "0225782089986669258803208183278659152741552450801685341843048568"
+ "1125008729650000322084879372381541270180139663134377177885154388"
+ "9558281508372272794193460069397070875763691455289959733530070186"
+ "0360525342531389354962332229432027179470095997955180502375530175"
+ "3"),
new BigInteger(
"6088560764944279853795552546797623009536823218028533977947580608"
+ "2015023514992395624319060987001625566234648211868300524182306472"
+ "7026872385780533326083682960047644674758988927136149502626557718"
+ "2561494515318563339483672950711193945073071458843901227339418284"
+ "3084182493461642555372639047162641075337152622892862251731700231"
+ "6672547426448574167370804559242233207791080547486632014153528258"
+ "1"),
new BigInteger(
"6081766267938901970682791123502557184373300073506187731779846380"
+ "4083193288475152882563422230130613717216469536080649276981712202"
+ "8895707724700107471391574673087393411637415445150131834443587280"
+ "4243131225731630921851260690656608624225797294197741881140769183"
+ "0474230365914155543155728342161658185646742117306992051014301383"
+ "8040790841165308968256142923362988225719340573836171022480960175"
+ "3"),
new BigInteger(
"5000879164859908887599881582814678322611278734193303790540199067"
+ "6946804876309491380295619810590406766227048051997595053442615914"
+ "2677702465219525342790323338314172797422380779526016709102650201"
+ "6058553529785304239405043134061167377896985489252957729348463979"
+ "6066933483020351454994081895283883114206539208013308687170796286"
+ "8268752695525736731805658439398227370325903928664994918343915975"
+ "3"),
new BigInteger(
"5033660524073962747735388920230339629907033897027296197974576730"
+ "5654422857706257645566447425553553516325935964234373316093019314"
+ "9125347663842235853602126989737378697014753612431648011618832921"
+ "3881347704723060451053853932258315572365588301231482715348124261"
+ "9244292433503547002496906691530720882968955274299548904791181715"
+ "4190217453383503386985567684902027707247767653326442247588135031"
+ "1"),
new BigInteger(
"7656692474335471169217545128846872228367812415627865759181393395"
+ "8241618825828371173259648247363305034462523584509943049089351382"
+ "5433879053475325827330864407124355159557574919864955631956757119"
+ "9044097578241324151657090338112756973390540016908863938814598847"
+ "5396824620980380695503598397306050849284639259137342875066075738"
+ "4060141031090753207116787791385102134328808638802350088507846845"
+ "1"),
new BigInteger(
"6916552449605114038869281931877716049700938960849845402874660241"
+ "3416574115770967736955518993475194932835724065347138687353620520"
+ "8331524408574865319265572656228099650675609929009824224767253657"
+ "5459382651810818256784829505942965567114371502731619372511210627"
+ "1610362520274480185346478545007812850057950851029848830710521787"
+ "8356932374617076535457900683468313279449103472700012568700849319"
+ "1"),
// F. Arnault, "Rabin-Miller primality test: composite numbers which pass it", Math. comp.
// v.64, n.209, p 355-361.
//
// A strong pseudoprime for the first 46 primes
new BigInteger(
"8038374574536394912570796143419421081388376882875581458374889175"
+ "2229742737653336521865023361639600454579150420236032087665699667"
+ "6098728404396540823292873879185086916685732826776177102938969773"
+ "9470167082304286871099974399765441448453411558724506334092790222"
+ "7529622941498423068816854043264575340183297861112989606448452161"
+ "91652872597534901"),
// Richard G.E. Pinch, Absolute quadratic pseudorprimes
// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.210.6783&rep=rep1&type=pdf
// Lucas-Charmichael-(-) numbers
new BigInteger("28295303263921"),
new BigInteger("443372888629441"),
new BigInteger("582920080863121"),
new BigInteger("894221105778001"),
new BigInteger("2013745337604001"),
// Lucas-Charmichael-(+) numbers
new BigInteger("6479"),
new BigInteger("84419"),
new BigInteger("1930499"),
new BigInteger("7110179"),
new BigInteger("15857855"),
new BigInteger("63278892599"),
new BigInteger("79397009999"),
};
/**
* Tests BigInteger.isProbablePrime with a list of composite integers. The integers have been
* chosen to check for weak pseudoprimality tests. E.g., they are counterexamples to weak
* implementations. The implementation in jdk uses a combination of a Miller-Rabin test and a
* Lucas test. This is similar to the Baillie-PSW test
* https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test
*/
public void testIsProbablePrime() throws Exception {
// The probability that a non-prime passes should be at most 1-2^{-certainty}.
int certainty = 80;
for (BigInteger n : NONPRIMES) {
if (n.isProbablePrime(certainty)) {
fail("Composite number " + n.toString() + " passed as probable prime test");
}
}
}
}
@@ -0,0 +1,279 @@
/**
* @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.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import junit.framework.TestCase;
/** CipherInputStream tests */
public class CipherInputStreamTest extends TestCase {
static final SecureRandom rand = new SecureRandom();
static byte[] randomBytes(int size) {
byte[] bytes = new byte[size];
rand.nextBytes(bytes);
return bytes;
}
static SecretKeySpec randomKey(String algorithm, int keySizeInBytes) {
return new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
}
static AlgorithmParameterSpec randomParameters(
String algorithm, int ivSizeInBytes, int tagSizeInBytes) {
if ("AES/GCM/NoPadding".equals(algorithm) || "AES/EAX/NoPadding".equals(algorithm)) {
return new GCMParameterSpec(8 * tagSizeInBytes, randomBytes(ivSizeInBytes));
}
return null;
}
/** Test vectors */
public static class TestVector {
public String algorithm;
public SecretKeySpec key;
public AlgorithmParameterSpec params;
public byte[] pt;
public byte[] aad;
public byte[] ct;
@SuppressWarnings("InsecureCipherMode")
public TestVector(
String algorithm, int keySize, int ivSize, int tagSize, int ptSize, int aadSize)
throws Exception {
this.algorithm = algorithm;
this.key = randomKey(algorithm, keySize);
this.params = randomParameters(algorithm, ivSize, tagSize);
this.pt = randomBytes(ptSize);
this.aad = randomBytes(aadSize);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.params);
cipher.updateAAD(aad);
this.ct = cipher.doFinal(pt);
}
}
Iterable<TestVector> getTestVectors(
String algorithm,
int[] keySizes,
int[] ivSizes,
int[] tagSizes,
int[] ptSizes,
int[] aadSizes)
throws Exception {
ArrayList<TestVector> result = new ArrayList<TestVector>();
for (int keySize : keySizes) {
for (int ivSize : ivSizes) {
for (int tagSize : tagSizes) {
for (int ptSize : ptSizes) {
for (int aadSize : aadSizes) {
result.add(new TestVector(algorithm, keySize, ivSize, tagSize, ptSize, aadSize));
}
}
}
}
}
return result;
}
@SuppressWarnings("InsecureCipherMode")
public void testEncrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.ENCRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
InputStream is = new ByteArrayInputStream(t.pt);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] result = new byte[t.ct.length];
int totalLength = 0;
int length = 0;
do {
length = cis.read(result, totalLength, result.length - totalLength);
if (length > 0) {
totalLength += length;
}
} while (length >= 0 && totalLength != result.length);
assertEquals(-1, cis.read());
assertEquals(TestUtil.bytesToHex(t.ct), TestUtil.bytesToHex(result));
cis.close();
}
}
/** JDK-8016249: CipherInputStream in decrypt mode fails on close with AEAD ciphers */
@SuppressWarnings("InsecureCipherMode")
public void testDecrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
InputStream is = new ByteArrayInputStream(t.ct);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] result = new byte[t.pt.length];
int totalLength = 0;
int length = 0;
do {
length = cis.read(result, totalLength, result.length - totalLength);
if (length > 0) {
totalLength += length;
}
} while (length >= 0 && totalLength != result.length);
assertEquals(-1, cis.read());
cis.close();
assertEquals(TestUtil.bytesToHex(t.pt), TestUtil.bytesToHex(result));
}
}
/**
* JDK-8016171 : CipherInputStream masks ciphertext tampering with AEAD ciphers in decrypt mode
* Further description of the bug is here:
* https://blog.heckel.xyz/2014/03/01/cipherinputstream-for-aead-modes-is-broken-in-jdk7-gcm/
* BouncyCastle claims that this bug is fixed in version 1.51. However, the test below still fails
* with BouncyCastle v 1.52. A possible explanation is that BouncyCastle has its own
* implemenatation of CipherInputStream (org.bouncycastle.crypto.io.CipherInputStream).
*/
@SuppressWarnings("InsecureCipherMode")
public void testCorruptDecrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
ct[ct.length - 1] ^= (byte) 1;
InputStream is = new ByteArrayInputStream(ct);
CipherInputStream cis = new CipherInputStream(is, cipher);
try {
byte[] result = new byte[t.pt.length];
int totalLength = 0;
int length = 0;
do {
length = cis.read(result, totalLength, result.length - totalLength);
if (length > 0) {
totalLength += length;
}
} while (length >= 0 && totalLength != result.length);
cis.close();
if (result.length > 0) {
fail(
"this should fail; decrypted:"
+ TestUtil.bytesToHex(result)
+ " pt: "
+ TestUtil.bytesToHex(t.pt));
}
} catch (IOException ex) {
// expected
}
}
}
@SuppressWarnings("InsecureCipherMode")
public void testCorruptDecryptEmpty(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
ct[ct.length - 1] ^= (byte) 1;
InputStream is = new ByteArrayInputStream(ct);
CipherInputStream cis = new CipherInputStream(is, cipher);
try {
byte[] result = new byte[t.pt.length];
int totalLength = 0;
int length = 0;
do {
length = cis.read(result, totalLength, result.length - totalLength);
if (length > 0) {
totalLength += length;
}
} while (length >= 0 && totalLength != result.length);
cis.close();
fail("this should fail");
} catch (IOException ex) {
// expected
}
}
}
public void testAesGcm() throws Exception {
final int[] keySizes = {16, 32};
final int[] ivSizes = {12};
final int[] tagSizes = {12, 16};
final int[] ptSizes = {0, 8, 16, 65, 8100};
final int[] aadSizes = {0, 8, 24};
Iterable<TestVector> v =
getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testEncrypt(v);
testDecrypt(v);
}
public void testCorruptAesGcm() throws Exception {
final int[] keySizes = {16, 32};
final int[] ivSizes = {12};
final int[] tagSizes = {12, 16};
final int[] ptSizes = {8, 16, 65, 8100};
final int[] aadSizes = {0, 8, 24};
Iterable<TestVector> v =
getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testCorruptDecrypt(v);
}
/**
* Unfortunately Oracle thinks that returning an empty array is valid behaviour for corrupt
* ciphertexts. Because of this we test empty plaintext separately to distinguish behaviour
* considered acceptable by Oracle from other behaviour.
*/
public void testEmptyPlaintext() throws Exception {
final int[] keySizes = {16, 32};
final int[] ivSizes = {12};
final int[] tagSizes = {12, 16};
final int[] ptSizes = {0};
final int[] aadSizes = {0, 8, 24};
Iterable<TestVector> v =
getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testCorruptDecryptEmpty(v);
}
/** Tests CipherOutputStream with AES-EAX if this algorithm is supported by the provider. */
public void testAesEax() throws Exception {
final String algorithm = "AES/EAX/NoPadding";
final int[] keySizes = {16, 32};
final int[] ivSizes = {12, 16};
final int[] tagSizes = {12, 16};
final int[] ptSizes = {0, 8, 16, 65, 8100};
final int[] aadSizes = {0, 8, 24};
try {
Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException ex) {
System.out.println("Skipping testAesEax");
return;
}
Iterable<TestVector> v =
getTestVectors(algorithm, keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testEncrypt(v);
testDecrypt(v);
testCorruptDecrypt(v);
}
}
@@ -0,0 +1,239 @@
/**
* @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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import junit.framework.TestCase;
/** CipherOutputStream tests */
public class CipherOutputStreamTest extends TestCase {
static final SecureRandom rand = new SecureRandom();
static byte[] randomBytes(int size) {
byte[] bytes = new byte[size];
rand.nextBytes(bytes);
return bytes;
}
static SecretKeySpec randomKey(String algorithm, int keySizeInBytes) {
return new SecretKeySpec(randomBytes(keySizeInBytes), "AES");
}
static AlgorithmParameterSpec randomParameters(
String algorithm, int ivSizeInBytes, int tagSizeInBytes) {
if ("AES/GCM/NoPadding".equals(algorithm) || "AES/EAX/NoPadding".equals(algorithm)) {
return new GCMParameterSpec(8 * tagSizeInBytes, randomBytes(ivSizeInBytes));
}
return null;
}
/** Test vectors */
@SuppressWarnings("InsecureCipherMode")
public static class TestVector {
public String algorithm;
public SecretKeySpec key;
public AlgorithmParameterSpec params;
public byte[] pt;
public byte[] aad;
public byte[] ct;
public TestVector(
String algorithm, int keySize, int ivSize, int tagSize, int ptSize, int aadSize)
throws Exception {
this.algorithm = algorithm;
this.key = randomKey(algorithm, keySize);
this.params = randomParameters(algorithm, ivSize, tagSize);
this.pt = randomBytes(ptSize);
this.aad = randomBytes(aadSize);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.params);
cipher.updateAAD(aad);
this.ct = cipher.doFinal(pt);
}
}
Iterable<TestVector> getTestVectors(
String algorithm,
int[] keySizes,
int[] ivSizes,
int[] tagSizes,
int[] ptSizes,
int[] aadSizes)
throws Exception {
ArrayList<TestVector> result = new ArrayList<TestVector>();
for (int keySize : keySizes) {
for (int ivSize : ivSizes) {
for (int tagSize : tagSizes) {
for (int ptSize : ptSizes) {
for (int aadSize : aadSizes) {
result.add(new TestVector(algorithm, keySize, ivSize, tagSize, ptSize, aadSize));
}
}
}
}
}
return result;
}
@SuppressWarnings("InsecureCipherMode")
public void testEncrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.ENCRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
ByteArrayOutputStream os = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(os, cipher);
cos.write(t.pt);
cos.close();
assertEquals(TestUtil.bytesToHex(t.ct), TestUtil.bytesToHex(os.toByteArray()));
}
}
@SuppressWarnings("InsecureCipherMode")
public void testDecrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
ByteArrayOutputStream os = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(os, cipher);
cos.write(t.ct);
cos.close();
assertEquals(TestUtil.bytesToHex(t.pt), TestUtil.bytesToHex(os.toByteArray()));
}
}
@SuppressWarnings("InsecureCipherMode")
public void testCorruptDecrypt(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
ct[ct.length - 1] ^= (byte) 1;
ByteArrayOutputStream os = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(os, cipher);
cos.write(ct);
try {
// cos.close() should call cipher.doFinal().
cos.close();
byte[] decrypted = os.toByteArray();
// Unfortunately Oracle thinks that returning an empty array is valid behaviour.
// We accept empty results here, but flag them in the next test, so that we can distinguish
// between beheviour considered acceptable by Oracle and more serious flaws.
if (decrypted.length > 0) {
fail(
"this should fail; decrypted:"
+ TestUtil.bytesToHex(decrypted)
+ " pt: "
+ TestUtil.bytesToHex(t.pt));
}
} catch (IOException ex) {
// expected
}
}
}
@SuppressWarnings("InsecureCipherMode")
public void testCorruptDecryptEmpty(Iterable<TestVector> tests) throws Exception {
for (TestVector t : tests) {
Cipher cipher = Cipher.getInstance(t.algorithm);
cipher.init(Cipher.DECRYPT_MODE, t.key, t.params);
cipher.updateAAD(t.aad);
byte[] ct = Arrays.copyOf(t.ct, t.ct.length);
ct[ct.length - 1] ^= (byte) 1;
ByteArrayOutputStream os = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(os, cipher);
cos.write(ct);
try {
// cos.close() should call cipher.doFinal().
cos.close();
byte[] decrypted = os.toByteArray();
fail(
"this should fail; decrypted:"
+ TestUtil.bytesToHex(decrypted)
+ " pt: "
+ TestUtil.bytesToHex(t.pt));
} catch (IOException ex) {
// expected
}
}
}
public void testAesGcm() throws Exception {
final int[] keySizes = {16, 32};
final int[] ivSizes = {12};
final int[] tagSizes = {12, 16};
final int[] ptSizes = {8, 16, 65, 8100};
final int[] aadSizes = {0, 8, 24};
Iterable<TestVector> v =
getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testEncrypt(v);
testDecrypt(v);
testCorruptDecrypt(v);
}
/**
* Unfortunately Oracle thinks that returning an empty array is valid behaviour for corrupt
* ciphertexts. Because of this we test empty plaintext separately to distinguish behaviour
* considered acceptable by Oracle from other behaviour.
*/
public void testEmptyPlaintext() throws Exception {
final int[] keySizes = {16, 32};
final int[] ivSizes = {12};
final int[] tagSizes = {12, 16};
final int[] ptSizes = {0};
final int[] aadSizes = {0, 8, 24};
Iterable<TestVector> v =
getTestVectors("AES/GCM/NoPadding", keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testEncrypt(v);
testDecrypt(v);
testCorruptDecryptEmpty(v);
}
/** Tests CipherOutputStream with AES-EAX if AES-EAS is supported by the provider. */
@SuppressWarnings("InsecureCipherMode")
public void testAesEax() throws Exception {
final String algorithm = "AES/EAX/NoPadding";
final int[] keySizes = {16, 32};
final int[] ivSizes = {12, 16};
final int[] tagSizes = {12, 16};
final int[] ptSizes = {8, 16, 65, 8100};
final int[] aadSizes = {0, 8, 24};
try {
Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException ex) {
System.out.println("Skipping testAesEax");
return;
}
Iterable<TestVector> v =
getTestVectors(algorithm, keySizes, ivSizes, tagSizes, ptSizes, aadSizes);
testEncrypt(v);
testDecrypt(v);
testCorruptDecrypt(v);
}
}
@@ -0,0 +1,396 @@
/**
* @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.ProviderType;
import com.google.security.wycheproof.WycheproofRunner.SlowTest;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;
import junit.framework.TestCase;
/**
* Testing Diffie-Hellman key agreement.
*
* <p>Subgroup confinment attacks:
* The papers by van Oorshot and Wiener rsp. Lim and Lee show that Diffie-Hellman keys can
* be found much faster if the short exponents are used and if the multiplicative group modulo p
* contains small subgroups. In particular an attacker can try to send a public key that is an
* element of a small subgroup. If the receiver does not check for such elements then may be
* possible to find the private key modulo the order of the small subgroup.
* Several countermeasures against such attacks have been proposed: For example IKE uses
* fields of order p where p is a safe prime (i.e. q=(p-1)/2), hence the only elements of small
* order are 1 and p-1.
* NIST SP 800-56A rev. 2, Section 5.5.1.1 only requires that the size of the subgroup generated
* by the generator g is big enough to prevent the baby-step giant-step algorithm. I.e. for 80-bit
* security p must be at least 1024 bits long and the prime q must be at least 160 bits long. A 2048
* bit prime p and a 224 bit prime q are sufficient for 112 bit security. To avoid subgroup
* confinment attacks NIST requires that public keys are validated, i.e. by checking that a public
* key y satisfies the conditions 2 <= y <= p-2 and y^q mod p == 1 (Section 5.6.2.3.1). Further,
* after generating the shared secret z = y_a ^ x_b mod p each party should check that z != 1. RFC
* 2785 contains similar recommendations.
* The public key validation described by NIST requires that the order q of the generator g
* is known to the verifier. Unfortunately, the order q is missing in PKCS #3. PKCS #3 describes
* the Diffie-Hellman parameters only by the values p, g and optionally the key size in bits.
*
* <p>The class DHParameterSpec that defines the Diffie-Hellman parameters in JCE contains the same
* values as PKCS#3. In particular, it does not contain the order of the subgroup q.
* Moreover, the SUN provider uses the minimal sizes specified by NIST for q.
* Essentially the provider reuses the parameters for DSA.
*
* <p>Therefore, there is no guarantee that an implementation of Diffie-Hellman is secure against
* subgroup confinement attacks. Without a key validation it is insecure to use the key-pair
* generation from NIST SP 800-56A Section 5.6.1.1 (The key-pair generation there only requires that
* static and ephemeral private keys are randomly chosen in the range 1..q-1).
*
* <p>To avoid big disasters the tests below require that key sizes are not minimal. I.e., currently
* the tests require at least 512 bit keys for 1024 bit fields. We use this lower limit because that
* is what the SUN provider is currently doing. TODO(bleichen): Find a reference supporting or
* disproving that decision.
*
* <p>References: P. C. van Oorschot, M. J. Wiener, "On Diffie-Hellman key agreement with short
* exponents", Eurocrypt 96, pp 332–343.
*
* <p>C.H. Lim and P.J. Lee, "A key recovery attack on discrete log-based schemes using a prime
* order subgroup", CRYPTO' 98, pp 249–263.
*
* <p>NIST SP 800-56A, revision 2, May 2013
* http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
*
* <p>PKCS #3, Diffie–Hellman Key Agreement
* http://uk.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm
*
* <p>RFC 2785, "Methods for Avoiding 'Small-Subgroup' Attacks on the Diffie-Hellman Key Agreement
* Method for S/MIME", March 2000
* https://www.ietf.org/rfc/rfc2785.txt
*
* <p>D. Adrian et al. "Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice"
* https://weakdh.org/imperfect-forward-secrecy-ccs15.pdf
* A good analysis of various DH implementations.
* Some misconfigurations pointed out in the paper are: p is composite, p-1 contains no large
* prime factor, q is used instead of the generator g.
*
* <p>Sources that might be used for additional tests:
*
* CVE-2015-3193: The Montgomery squaring implementation in crypto/bn/asm/x86_64-mont5.pl
* in OpenSSL 1.0.2 before 1.0.2e on the x86_64 platform, as used by the BN_mod_exp function,
* mishandles carry propagation
* https://blog.fuzzing-project.org/31-Fuzzing-Math-miscalculations-in-OpenSSLs-BN_mod_exp-CVE-2015-3193.html
*
* <p>CVE-2016-0739: libssh before 0.7.3 improperly truncates ephemeral secrets generated for the
* (1) diffie-hellman-group1 and (2) diffie-hellman-group14 key exchange methods to 128 bits ...
*
* <p>CVE-2015-1787 The ssl3_get_client_key_exchange function in s3_srvr.c in OpenSSL 1.0.2 before
* 1.0.2a, when client authentication and an ephemeral Diffie-Hellman ciphersuite are enabled,
* allows remote attackers to cause a denial of service (daemon crash) via a ClientKeyExchange
* message with a length of zero.
*
* <p>CVE-2015-0205 The ssl3_get_cert_verify function in s3_srvr.c in OpenSSL 1.0.0 before 1.0.0p
* and 1.0.1 before 1.0.1k accepts client authentication with a Diffie-Hellman (DH) certificate
* without requiring a CertificateVerify message, which allows remote attackers to obtain access
* without knowledge of a private key via crafted TLS Handshake Protocol traffic to a server that
* recognizes a Certification Authority with DH support.
*
* <p>CVE-2016-0701 The DH_check_pub_key function in crypto/dh/dh_check.c in OpenSSL 1.0.2 before
* 1.0.2f does not ensure that prime numbers are appropriate for Diffie-Hellman (DH) key exchange,
* which makes it easier for remote attackers to discover a private DH exponent by making multiple
* handshakes with a peer that chose an inappropriate number, as demonstrated by a number in an
* X9.42 file.
*
* <p>CVE-2006-1115 nCipher HSM before 2.22.6, when generating a Diffie-Hellman public/private key
* pair without any specified DiscreteLogGroup parameters, chooses random parameters that could
* allow an attacker to crack the private key in significantly less time than a brute force attack.
*
* <p>CVE-2015-1716 Schannel in Microsoft Windows Server 2003 SP2, Windows Vista SP2, Windows Server
* 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and
* Windows RT Gold and 8.1 does not properly restrict Diffie-Hellman Ephemeral (DHE) key lengths,
* which makes it easier for remote attackers to defeat cryptographic protection mechanisms via
* unspecified vectors, aka "Schannel Information Disclosure Vulnerability.
*
* <p>CVE-2015-2419: Random generation of the prime p allows Pohlig-Hellman and probably other
* stuff.
*
* <p> J. Fried et al. "A kilobit hidden SNFS discrete logarithm computation".
* http://eprint.iacr.org/2016/961.pdf
* Some crypto libraries use fields that can be broken with the SNFS.
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
public class DhTest extends TestCase {
public DHParameterSpec ike1536() {
final BigInteger p =
new BigInteger(
"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
+ "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
+ "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
+ "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
+ "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
+ "9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff",
16);
final BigInteger g = new BigInteger("2");
return new DHParameterSpec(p, g);
}
public DHParameterSpec ike2048() {
final BigInteger p =
new BigInteger(
"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
+ "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
+ "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
+ "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
+ "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
+ "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b"
+ "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718"
+ "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff",
16);
final BigInteger g = new BigInteger("2");
return new DHParameterSpec(p, g);
}
// The default parameters returned for 1024 bit DH keys from OpenJdk as defined in
// openjdk7/releases/v6/trunk/jdk/src/share/classes/sun/security/provider/ParameterCache.java
// I.e., these are the same parameters as used for DSA.
public DHParameterSpec openJdk1024() {
final BigInteger p =
new BigInteger(
"fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669"
+ "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7"
+ "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb"
+ "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7",
16);
final BigInteger unusedQ = new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16);
final BigInteger g =
new BigInteger(
"f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267"
+ "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1"
+ "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b"
+ "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a",
16);
return new DHParameterSpec(p, g);
}
/** Check that key agreement using DH works. */
public void testDh() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
DHParameterSpec dhparams = ike2048();
keyGen.initialize(dhparams);
KeyPair keyPairA = keyGen.generateKeyPair();
KeyPair keyPairB = keyGen.generateKeyPair();
KeyAgreement kaA = KeyAgreement.getInstance("DH");
KeyAgreement kaB = KeyAgreement.getInstance("DH");
kaA.init(keyPairA.getPrivate());
kaB.init(keyPairB.getPrivate());
kaA.doPhase(keyPairB.getPublic(), true);
kaB.doPhase(keyPairA.getPublic(), true);
byte[] kAB = kaA.generateSecret();
byte[] kBA = kaB.generateSecret();
assertEquals(TestUtil.bytesToHex(kAB), TestUtil.bytesToHex(kBA));
}
/**
* Returns the product of primes that can be found by a simple variant of Pollard-rho.
* The result should contain all prime factors of n smaller than 10^8.
* This method is heuristic, since it could in principle find large prime factors too.
* However, for a random 160-bit prime q the probability of this should be less than 2^{-100}.
*/
private BigInteger smoothDivisor(BigInteger n) {
// By examination we verified that for every prime p < 10^8
// the iteration x_n = x_{n-1}^2 + 1 mod p enters a cycle of size < 50000 after at
// most 50000 steps.
int pollardRhoSteps = 50000;
BigInteger u = new BigInteger("2");
for (int i = 0; i < pollardRhoSteps; i++) {
u = u.multiply(u).add(BigInteger.ONE).mod(n);
}
BigInteger v = u;
BigInteger prod = BigInteger.ONE;
for (int i = 0; i < pollardRhoSteps; i++) {
v = v.multiply(v).add(BigInteger.ONE).mod(n);
// This implementation is only looking for the product of small primes.
// Therefore, instead of continuously computing gcds of v-u and n, it is sufficient
// and more efficient to compute the product of of v-u for all v and compute the gcd
// at the end.
prod = prod.multiply(v.subtract(u).abs()).mod(n);
}
BigInteger result = BigInteger.ONE;
while (true) {
BigInteger f = n.gcd(prod);
if (f.equals(BigInteger.ONE)) {
return result;
}
result = result.multiply(f);
n = n.divide(f);
}
}
@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);
BigInteger r; // p-1 divided by small prime factors.
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);
// DH parameters are sometime misconfigures and g and q are swapped.
// A large g that divides p-1 is suspicious.
if (g.bitLength() >= 160) {
assertTrue(p.mod(g).compareTo(BigInteger.ONE) > 0);
}
}
/**
* Tests Diffie-Hellman key pair generation.
*
* <p> This is a slow test since some providers (e.g. BouncyCastle) generate new safe primes
* for each new key.
*/
public void testKeyPairGenerator() throws Exception {
int keySize = 1024;
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
keyGen.initialize(keySize);
KeyPair keyPair = keyGen.generateKeyPair();
testKeyPair(keyPair, keySize);
}
/** This test tries a key agreement with keys using distinct parameters. */
public void testDHDistinctParameters() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
keyGen.initialize(ike1536());
KeyPair keyPairA = keyGen.generateKeyPair();
keyGen.initialize(ike2048());
KeyPair keyPairB = keyGen.generateKeyPair();
KeyAgreement kaA = KeyAgreement.getInstance("DH");
kaA.init(keyPairA.getPrivate());
try {
kaA.doPhase(keyPairB.getPublic(), true);
byte[] kAB = kaA.generateSecret();
fail("Generated secrets with mixed keys " + TestUtil.bytesToHex(kAB) + ", ");
} catch (java.security.GeneralSecurityException ex) {
// This is expected.
}
}
/**
* Tests whether a provider accepts invalid public keys that result in predictable shared secrets.
* This test is based on RFC 2785, Section 4 and NIST SP 800-56A, If an attacker can modify both
* public keys in an ephemeral-ephemeral key agreement scheme then it may be possible to coerce
* both parties into computing the same predictable shared key.
*
* <p> Note: the test is quite whimsical. If the prime p is not a safe prime then the provider
* itself cannot prevent all small-subgroup attacks because of the missing parameter q in the
* Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones
* proposed in RFC 2785.
*/
public void testSubgroupConfinement() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
DHParameterSpec params = ike2048();
BigInteger p = params.getP();
BigInteger g = params.getG();
keyGen.initialize(params);
PrivateKey priv = keyGen.generateKeyPair().getPrivate();
KeyAgreement ka = KeyAgreement.getInstance("DH");
BigInteger[] weakPublicKeys = {
BigInteger.ZERO,
BigInteger.ONE,
p.subtract(BigInteger.ONE),
p,
p.add(BigInteger.ONE),
BigInteger.ONE.negate()
};
for (BigInteger weakKey : weakPublicKeys) {
ka.init(priv);
try {
KeyFactory kf = KeyFactory.getInstance("DH");
DHPublicKeySpec weakSpec = new DHPublicKeySpec(weakKey, p, g);
PublicKey pub = kf.generatePublic(weakSpec);
ka.doPhase(pub, true);
byte[] kAB = ka.generateSecret();
fail(
"Generated secrets with weak public key:"
+ weakKey.toString()
+ " secret:"
+ TestUtil.bytesToHex(kAB));
} catch (GeneralSecurityException ex) {
// this is expected
}
}
}
}
@@ -0,0 +1,157 @@
/**
* @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.ProviderType;
import com.google.security.wycheproof.WycheproofRunner.SlowTest;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;
import junit.framework.TestCase;
/**
* Testing DHIES.
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
// Tested providers:
// BC (not recommended)
//
// TODO(bleichen):
// - maybe again CipherInputStream, CipherOutputStream,
// - byteBuffer.
// - Exception handling
// - Is DHIES using the key derivation function for the key stream?
// - BouncyCastle knows an algorithm IES. Is this the same as DHIES?
public class DhiesTest extends TestCase {
// TODO(bleichen): This is the same as DhTest.java
// We could move this into some TestUtil.
public DHParameterSpec ike2048() {
final BigInteger p =
new BigInteger(
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
16);
final BigInteger g = new BigInteger("2");
return new DHParameterSpec(p, g);
}
/**
* WARNING: This test uses weak crypto (i.e. DHIESWithAES). Checks that key agreement using DHIES
* works in the sense that it can decrypt what it encrypts. Unfortunately it seems that there is
* no secure mode using AES.
*/
@SuppressWarnings("InsecureCipherMode")
public void testDhiesBasic() throws Exception {
DHParameterSpec params = ike2048();
KeyPairGenerator kf = KeyPairGenerator.getInstance("DH");
kf.initialize(params);
KeyPair keyPair = kf.generateKeyPair();
PrivateKey priv = keyPair.getPrivate();
PublicKey pub = keyPair.getPublic();
byte[] message = "Hello".getBytes("UTF-8");
Cipher dhies = Cipher.getInstance("DHIESwithAES");
dhies.init(Cipher.ENCRYPT_MODE, pub);
byte[] ciphertext = dhies.doFinal(message);
System.out.println("testDhiesBasic:" + TestUtil.bytesToHex(ciphertext));
dhies.init(Cipher.DECRYPT_MODE, priv);
byte[] decrypted = dhies.doFinal(ciphertext);
assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
}
/**
* 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("InsecureCipherMode")
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 = Cipher.getInstance("DHIESwithAES");
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
}
}
}
/**
* Tries to detect if an algorithm is using ECB. Unfortunately, many JCE algorithms use ECB if no
* encryption mode is specified.
*/
@SuppressWarnings("InsecureCipherMode")
public void testNotEcb(String algorithm) throws Exception {
Cipher dhies;
try {
dhies = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException ex) {
// This test is called with short algorithm names such as just "DHIES".
// Requiring full names is typically a good practice. Hence it is OK
// to not assigning default algorithms.
System.out.println("No implementation for:" + algorithm);
return;
}
KeyPairGenerator kf = KeyPairGenerator.getInstance("DH");
kf.initialize(ike2048());
KeyPair keyPair = kf.generateKeyPair();
PublicKey pub = keyPair.getPublic();
byte[] message = new byte[512];
dhies.init(Cipher.ENCRYPT_MODE, pub);
byte[] ciphertext = dhies.doFinal(message);
for (int i = 0; i + 32 <= ciphertext.length; i++) {
String block1 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, i, i + 16));
String block2 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, i + 16, i + 32));
assertTrue(
"Ciphertext repeats at " + i + ":" + TestUtil.bytesToHex(ciphertext),
!block1.equals(block2));
}
}
public void testSemanticSecurityDhies() throws Exception {
testNotEcb("DHIES");
}
}
@@ -0,0 +1,655 @@
/**
* @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.
*/
// TODO(bleichen):
// - add tests for SHA1WithDSA with wrong key
// - add tests for "alternative" algorithm names
// - convert tests for deterministic DSA variants.
// Deterministic DSA has a few new drawbacks:
// * implementations flaws that generate k incorrectly can leak
// the key if multiple implementations (e.g. one correct one incorrect)
// is used.
// * timing attacks are more serious if the attacker can ask for the same
// signature multiple times, since this allows to get more accurate timings.
package com.google.security.wycheproof;
import com.google.security.wycheproof.WycheproofRunner.ProviderType;
import com.google.security.wycheproof.WycheproofRunner.SlowTest;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import junit.framework.TestCase;
/**
* Tests DSA against invalid signatures. The motivation for this test is the DSA implementation in
* gpg4browsers. This implementation accepts signatures with r=1 and s=0 as valid.
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
// Tested providers:
// "SUN":
// - allows some alternative BER encodings of signatures
// - does not check whether the ASN sequence contains two elements
// and throws runtime exceptions when the sequence is too short.
// - does not support 3072 bit keys.
// "BC":
// - allows some alternaitve BER encodings
// - accepts signatures with additional arguments
// - key generation is slow, maybe because BouncyCastle tries to generate
// new parameters for each key.
// - KeyPairGenerator.getInstance("DSA") generates keys with 160 bit q
// independent of the size of p.
public class DsaTest extends TestCase {
static final String MESSAGE = "Hello";
static final DSAPrivateKeySpec privateKey1 =
new DSAPrivateKeySpec(
// x
new BigInteger("15382583218386677486843706921635237927801862255437148328980464126979"),
// p
new BigInteger(
"181118486631420055711787706248812146965913392568235070235446058914"
+ "1170708161715231951918020125044061516370042605439640379530343556"
+ "4101919053459832890139496933938670005799610981765220283775567361"
+ "4836626483403394052203488713085936276470766894079318754834062443"
+ "1033792580942743268186462355159813630244169054658542719322425431"
+ "4088256212718983105131138772434658820375111735710449331518776858"
+ "7867938758654181244292694091187568128410190746310049564097068770"
+ "8161261634790060655580211122402292101772553741704724263582994973"
+ "9109274666495826205002104010355456981211025738812433088757102520"
+ "562459649777989718122219159982614304359"),
// q
new BigInteger("19689526866605154788513693571065914024068069442724893395618704484701"),
// g
new BigInteger(
"2859278237642201956931085611015389087970918161297522023542900348"
+ "0877180630984239764282523693409675060100542360520959501692726128"
+ "3149190229583566074777557293475747419473934711587072321756053067"
+ "2532404847508798651915566434553729839971841903983916294692452760"
+ "2490198571084091890169933809199002313226100830607842692992570749"
+ "0504363602970812128803790973955960534785317485341020833424202774"
+ "0275688698461842637641566056165699733710043802697192696426360843"
+ "1736206792141319514001488556117408586108219135730880594044593648"
+ "9237302749293603778933701187571075920849848690861126195402696457"
+ "4111219599568903257472567764789616958430"));
static final DSAPublicKeySpec publicKey1 =
new DSAPublicKeySpec(
new BigInteger(
"3846308446317351758462473207111709291533523711306097971550086650"
+ "2577333637930103311673872185522385807498738696446063139653693222"
+ "3528823234976869516765207838304932337200968476150071617737755913"
+ "3181601169463467065599372409821150709457431511200322947508290005"
+ "1780020974429072640276810306302799924668893998032630777409440831"
+ "4314588994475223696460940116068336991199969153649625334724122468"
+ "7497038281983541563359385775312520539189474547346202842754393945"
+ "8755803223951078082197762886933401284142487322057236814878262166"
+ "5072306622943221607031324846468109901964841479558565694763440972"
+ "5447389416166053148132419345627682740529"),
privateKey1.getP(),
privateKey1.getQ(),
privateKey1.getG());
// Signatures for Key1.
static final String[] VALID_SIGNATURES = {
"303d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd"
+ "021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813fe8786236",
};
// The following test vectors check for signature malleability and bugs.
// That means the test vectors are derived from a valid signature
// by modifying the ASN encoding. A correct implementation of DSA
// should only accept correct DER encoding and properly handle the others.
// Allowing alternative BER encodings is in many cases benign.
// An example where this kind of signature malleability was a problem
// https://en.bitcoin.it/wiki/Transaction_Malleability
static final String[] INVALID_SIGNATURES = {
// encodings that were obtained by leaving some arguments out
"301f021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813fe87862" + "36",
"301e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd",
"",
// encodings that were obtained by leaving some parts empty
"30210200021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813fe8" + "786236",
"3020021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd" + "0200",
"3000",
// encodings with sizes that overflow 32 or 64 bit integers
"30420285010000001c1e41b479ad576905b960fe14eadb91b0ccf34843dab916"
+ "173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f"
+ "e8786236",
"3046028901000000000000001c1e41b479ad576905b960fe14eadb91b0ccf348"
+ "43dab916173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf"
+ "3365813fe8786236",
"3042021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd"
+ "0285010000001d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f"
+ "e8786236",
"3046021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd"
+ "028901000000000000001d00ade65988d237d30f9ef41dd424a4e1c8f16967cf"
+ "3365813fe8786236",
"3085010000003d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916"
+ "173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f"
+ "e8786236",
"308901000000000000003d021c1e41b479ad576905b960fe14eadb91b0ccf348"
+ "43dab916173bb8c9cd021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf"
+ "3365813fe8786236",
// encodings where numbers were replace by an encoding of infinity
"3022090180021d00ade65988d237d30f9ef41dd424a4e1c8f16967cf3365813f" + "e8786236",
"3021021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd" + "090180",
// Signatures with special case values for r and s.
// E.g. r=1, s=0 are values that can lead to forgeries if the DSA implementation
// does not check boundaries and computes s^(-1) == 0.
"300402000200",
"30050200020101",
"300502000201ff",
"30210200021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc" + "d5695d",
"30210200021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc" + "d5695e",
"30210200021d0100000000000000000000000000000000000000000000000000" + "000000",
"30820107020002820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3b"
+ "af3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85"
+ "d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a9934534"
+ "09a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d"
+ "648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d81"
+ "81e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f80"
+ "3b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b"
+ "66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342"
+ "be484c05763939601cd667",
"30070200090380fe01",
"30050201010200",
"3006020101020101",
"30060201010201ff",
"3022020101021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695d",
"3022020101021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695e",
"3022020101021d01000000000000000000000000000000000000000000000000" + "00000000",
"3082010802010102820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e"
+ "3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b"
+ "85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a99345"
+ "3409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f"
+ "9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d"
+ "8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f"
+ "803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de"
+ "4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e3"
+ "42be484c05763939601cd667",
"3008020101090380fe01",
"30050201ff0200",
"30060201ff020101",
"30060201ff0201ff",
"30220201ff021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695d",
"30220201ff021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0" + "bcd5695e",
"30220201ff021d01000000000000000000000000000000000000000000000000" + "00000000",
"308201080201ff02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e"
+ "3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b"
+ "85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a99345"
+ "3409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f"
+ "9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d"
+ "8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f"
+ "803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de"
+ "4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e3"
+ "42be484c05763939601cd667",
"30080201ff090380fe01",
"3021021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d0200",
"3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d020101",
"3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d0201ff",
"303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ "5d021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695d",
"303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ "5d021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695e",
"303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ "5d021d0100000000000000000000000000000000000000000000000000000000",
"30820124021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc"
+ "d5695d02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf3718"
+ "e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011ad"
+ "b8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0fe"
+ "696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648ef8"
+ "83448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e733"
+ "8db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32a4"
+ "c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff04"
+ "903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be484c"
+ "05763939601cd667",
"3024021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5d090380fe01",
"3021021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e0200",
"3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e020101",
"3022021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e0201ff",
"303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ "5e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695d",
"303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ "5e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695e",
"303e021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569"
+ "5e021d0100000000000000000000000000000000000000000000000000000000",
"30820124021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bc"
+ "d5695e02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf3718"
+ "e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011ad"
+ "b8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0fe"
+ "696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648ef8"
+ "83448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e733"
+ "8db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32a4"
+ "c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff04"
+ "903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be484c"
+ "05763939601cd667",
"3024021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd569" + "5e090380fe01",
"3021021d01000000000000000000000000000000000000000000000000000000" + "000200",
"3022021d01000000000000000000000000000000000000000000000000000000" + "00020101",
"3022021d01000000000000000000000000000000000000000000000000000000" + "000201ff",
"303e021d01000000000000000000000000000000000000000000000000000000"
+ "00021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695d",
"303e021d01000000000000000000000000000000000000000000000000000000"
+ "00021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae580c0bcd5695e",
"303e021d01000000000000000000000000000000000000000000000000000000"
+ "00021d0100000000000000000000000000000000000000000000000000000000",
"30820124021d0100000000000000000000000000000000000000000000000000"
+ "00000002820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf3718"
+ "e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011ad"
+ "b8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0fe"
+ "696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648ef8"
+ "83448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e733"
+ "8db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32a4"
+ "c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff04"
+ "903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be484c"
+ "05763939601cd667",
"3024021d01000000000000000000000000000000000000000000000000000000" + "00090380fe01",
"3082010702820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd6670200",
"3082010802820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd667020101",
"3082010802820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd6670201ff",
"3082012402820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd667021d00baf696a68578f7dfdee7fa67c977c785ef32b233"
+ "bae580c0bcd5695d",
"3082012402820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd667021d00baf696a68578f7dfdee7fa67c977c785ef32b233"
+ "bae580c0bcd5695e",
"3082012402820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd667021d010000000000000000000000000000000000000000"
+ "0000000000000000",
"3082020a02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd66702820101008f7935d9b9aae9bfabed887acf4951b6f32e"
+ "c59e3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7"
+ "475b85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a9"
+ "93453409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6"
+ "291f9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9f"
+ "fa9d8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633"
+ "458f803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea1"
+ "43de4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f8"
+ "22e342be484c05763939601cd667",
"3082010a02820101008f7935d9b9aae9bfabed887acf4951b6f32ec59e3baf37"
+ "18e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7475b85d011"
+ "adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a993453409a0"
+ "fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6291f9d648e"
+ "f883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9ffa9d8181e7"
+ "338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633458f803b32"
+ "a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea143de4b66ff"
+ "04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f822e342be48"
+ "4c05763939601cd667090380fe01",
"3007090380fe010200",
"3008090380fe01020101",
"3008090380fe010201ff",
"3024090380fe01021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae5" + "80c0bcd5695d",
"3024090380fe01021d00baf696a68578f7dfdee7fa67c977c785ef32b233bae5" + "80c0bcd5695e",
"3024090380fe01021d0100000000000000000000000000000000000000000000" + "000000000000",
"3082010a090380fe0102820101008f7935d9b9aae9bfabed887acf4951b6f32e"
+ "c59e3baf3718e8eac4961f3efd3606e74351a9c4183339b809e7c2ae1c539ba7"
+ "475b85d011adb8b47987754984695cac0e8f14b3360828a22ffa27110a3d62a9"
+ "93453409a0fe696c4658f84bdd20819c3709a01057b195adcd00233dba5484b6"
+ "291f9d648ef883448677979cec04b434a6ac2e75e9985de23db0292fc1118c9f"
+ "fa9d8181e7338db792b730d7b9e349592f68099872153915ea3d6b8b4653c633"
+ "458f803b32a4c2e0f27290256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea1"
+ "43de4b66ff04903ed5cf1623e158d487c608e97f211cd81dca23cb6e380765f8"
+ "22e342be484c05763939601cd667",
"300a090380fe01090380fe01",
};
public void testVectors(
String[] signatures,
DSAPublicKeySpec key,
String message,
String algorithm,
String signatureType,
boolean isValid)
throws Exception {
byte[] messageBytes = "Hello".getBytes("UTF-8");
Signature verifier = Signature.getInstance(algorithm);
KeyFactory kf = KeyFactory.getInstance("DSA");
PublicKey pub = kf.generatePublic(key);
int errors = 0;
for (String signature : signatures) {
byte[] signatureBytes = TestUtil.hexToBytes(signature);
verifier.initVerify(pub);
verifier.update(messageBytes);
boolean verified = false;
try {
verified = verifier.verify(signatureBytes);
} catch (SignatureException ex) {
// verify can throw SignatureExceptions if the signature is malformed.
// We don't flag these cases and simply consider the signature as invalid.
verified = false;
} catch (Exception ex) {
// Other exceptions indicate some internal error, e.g. careless ASN parsing.
// We count these as errors.
System.out.println(signatureType + ":" + signature + " throws:" + ex.toString());
errors++;
continue;
}
if (isValid && !verified) {
System.out.println(signatureType + " was not verified:" + signature);
errors++;
} else if (!isValid && verified) {
System.out.println(signatureType + " was verified:" + signature);
errors++;
}
}
assertEquals(0, errors);
}
public void testValidSignatures() throws Exception {
testVectors(
VALID_SIGNATURES, publicKey1, "Hello", "SHA224WithDSA", "Valid DSA signature", true);
}
// Extract the integer r from a DSA signature.
// This method implicitely assumes that the DSA signature is DER encoded.
BigInteger extractR(byte[] signature) throws Exception {
int lengthR = signature[3];
return new BigInteger(Arrays.copyOfRange(signature, 4, 4 + lengthR));
}
BigInteger extractS(byte[] signature) throws Exception {
int lengthR = signature[3];
int startS = 4 + lengthR;
int lengthS = signature[startS + 1];
return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS));
}
/** Extract the k that was used to sign the signature. Validates the k if check == true. */
BigInteger extractK(byte[] signature, BigInteger h, DSAPrivateKey priv, boolean check)
throws Exception {
BigInteger x = priv.getX();
BigInteger q = priv.getParams().getQ();
BigInteger r = extractR(signature);
BigInteger s = extractS(signature);
BigInteger k = x.multiply(r).add(h).multiply(s.modInverse(q)).mod(q);
if (check) {
BigInteger p = priv.getParams().getP();
BigInteger g = priv.getParams().getG();
BigInteger r2 = g.modPow(k, p).mod(q);
assertEquals(r.toString(), r2.toString());
}
return k;
}
/**
* Providers that implement SHA1WithDSA but not at least SHA256WithDSA are outdated and should be
* avoided even if DSA is currently not used in a project. Such providers promote using a weak
* signature scheme. It can also "inspire" developers to use invalid schemes such as SHA1WithDSA
* together with 2048-bit key. Such invalid use cases are often untested and can have serious
* flaws. For example the SUN provider leaked the private keys with 3 to 5 signatures in such
* instances.
*/
public void testOutdatedProvider() throws Exception {
try {
Signature sig = Signature.getInstance("SHA1WithDSA");
try {
Signature.getInstance("SHA256WithDSA");
} catch (NoSuchAlgorithmException ex) {
fail("Provider " + sig.getProvider().getName() + " is outdated and should not be used.");
}
} catch (NoSuchAlgorithmException ex) {
System.out.println("SHA1WithDSA is not supported");
}
}
/**
* 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})
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());
}
/**
* Checks whether the one time key k in DSA is biased. For example the SUN provider fell for this
* test until April 2016.
*/
public void testDsaBias() throws Exception {
// q is close to 2/3 * 2^160.
BigInteger q = new BigInteger("974317976835659416858874959372334979171063697271");
BigInteger p =
new BigInteger(
"1106803511314772711673172950296693567629309594518393175860816428"
+ "6658764043763662129010863568011543182924292444458455864283745070"
+ "9908516713302345161980412667892373845670780253725557376379049862"
+ "4062950082444499320797079243439689601679418602390654466821968220"
+ "32212146727497041502702331623782703855119908989712161");
BigInteger g =
new BigInteger(
"1057342118316953575810387190942009018497979302261477972033090351"
+ "7561815639397594841480480197745063606756857212792356354588585967"
+ "3837265237205154744016475608524531648654928648461175919672511710"
+ "4878976887505840764543501512668232945506391524642105449699321960"
+ "32410302985148400531470153936516167243072120845392903");
BigInteger x = new BigInteger("13706102843888006547723575730792302382646994436");
KeyFactory kf = KeyFactory.getInstance("DSA");
DSAPrivateKey priv = (DSAPrivateKey) kf.generatePrivate(new DSAPrivateKeySpec(x, p, q, g));
// If we make TESTS tests with a fair coin then the probability that
// either heads or tails appears less than MINCOUNT times is less than
// 2^{-32}.
// I.e. 2*sum(binomial(tests,i) for i in range(mincount))*2**32 < 2**tests
// Therefore the test below is not expected to fail unless the generation
// of the one time keys is indeed biased.
final int tests = 1024;
final int mincount = 410;
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);
final BigInteger qHalf = q.shiftRight(1);
Signature signer = Signature.getInstance("SHA1WithDSA");
signer.initSign(priv);
int countLsb = 0; // count the number of k's with msb set
int countMsb = 0; // count the number of k's with lsb set
for (int i = 0; i < tests; i++) {
signer.update(messageBytes);
byte[] signature = signer.sign();
BigInteger k = extractK(signature, h, priv, i < 10);
if (k.testBit(0)) {
countLsb++;
}
if (k.compareTo(qHalf) == 1) {
countMsb++;
}
}
if (countLsb < mincount || countLsb > tests - mincount) {
fail("Bias detected in the least significant bit of k:" + countLsb);
}
if (countMsb < mincount || countMsb > tests - mincount) {
fail("Bias detected in the most significant bit of k:" + countMsb);
}
}
/**
* 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})
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;
}
}
/**
* DSA does not allow encryption. This test verifies that a provider does not implement an ad hoc
* scheme that attempts to turn DSA into a public key encryption scheme.
*/
@SuppressWarnings("InsecureCipherMode")
public void testEncryptionWithDsa() throws Exception {
try {
Cipher cipher = Cipher.getInstance("DSA");
fail("DSA must not be used as a cipher:" + cipher.getProvider().toString());
} catch (NoSuchAlgorithmException ex) {
// This is expected
}
}
}
@@ -0,0 +1,230 @@
/**
* @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.
*/
// TODO(bleichen): RFC 3279 allows ECKeys with a number of different parameters.
// E.g. public keys can specify the order, base points etc.
// We might want to check how well these parameters are verified when parsing
// a public key.
package com.google.security.wycheproof;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import junit.framework.TestCase;
/** EC tests */
public class EcKeyTest extends TestCase {
/**
* Encodings of public keys with invalid parameters. There are multiple places where a provider
* can validate a public key: some parameters are typically validated by the KeyFactory, more
* validation can be done by the cryptographic primitive. Unused parameters are sometimes not
* validated at all.
*
* <p>This following test vectors are public key encodings with invalid parameters where we expect
* that KeyFactory.generatePublic recognizes the problem. The documentation simply claims that an
* InvalidKeySpecException is thrown if the given key specification is inappropriate but does not
* specify what an appropriate key exactly is. Nonetheless we expect that the following minimal
* validations are performed: order is a positive integer, cofactor is a small positive integer.
* Some modifications may not be detected and must be caught by the primitives using them. E.g.,
* it is expensive to verify the order of the group generated by the generator and hence the key
* factory may not verify the correctness of this parameter. Thus an implementation of ECDH must
* not trust an order claimed in the public key.
*
* <p>TODO(bleichen): The encoding is defined in https://tools.ietf.org/html/rfc3279 Section
* 2.3.5. This document defines a few additional requirements and options which are not yet
* checked: - OID for id-public-key_type must be ansi-X9.62 2 - OID for id-ecPublicKey must be
* id-publicKeyType 1 - The intended application for the key may be indicated in the key usage
* field (RFC 3280). - EcpkParameters can be implicitlyCA (not sure how we would specify the curve
* in this case) - the version is always 1 - the points on the curves can be either compressed or
* uncompressed (so far all points are uncompressed) - the seed value is optional (so far no test
* vector specifies the seed) - the cofactor is optional but must be included for ECDH keys. (so
* far all test vectors have a cofactor)
*
* <p>RFC 3279 also specifies curves over binary fields. Because of attacks against such curves,
* i.e. "New algorithm for the discrete logarithm problem on elliptic curves" by I.Semaev
* https://eprint.iacr.org/2015/310 such curves should no longer be used and hence testing them
* has low priority.
*/
public static final String[] EC_INVALID_PUBLIC_KEYS = {
// order = -115792089210356248762697446949407573529996955224135760342422259061068512044369
"308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ "576b315ececbb6406837bf51f50221ff00000000ffffffff0000000000000000"
+ "4319055258e8617b0c46353d039cdaaf02010103420004cdeb39edd03e2b1a11"
+ "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
// order = 0
"308201123081cb06072a8648ce3d02013081bf020101302c06072a8648ce3d01"
+ "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ "576b315ececbb6406837bf51f5020002010103420004cdeb39edd03e2b1a11a5"
+ "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
+ "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
// cofactor = -1
"308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
+ "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ "bce6faada7179e84f3b9cac2fc6325510201ff03420004cdeb39edd03e2b1a11"
+ "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
+ "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
// cofactor = 0
"308201323081eb06072a8648ce3d02013081df020101302c06072a8648ce3d01"
+ "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
+ "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
+ "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
+ "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
+ "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
+ "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
+ "bce6faada7179e84f3b9cac2fc632551020003420004cdeb39edd03e2b1a11a5"
+ "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
+ "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
// cofactor = 115792089210356248762697446949407573529996955224135760342422259061068512044369
"308201553082010d06072a8648ce3d020130820100020101302c06072a8648ce"
+ "3d0101022100ffffffff00000001000000000000000000000000ffffffffffff"
+ "ffffffffffff30440420ffffffff00000001000000000000000000000000ffff"
+ "fffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0"
+ "cc53b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277"
+ "037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162b"
+ "ce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffff"
+ "ffffbce6faada7179e84f3b9cac2fc632551022100ffffffff00000000ffffff"
+ "ffffffffffbce6faada7179e84f3b9cac2fc63255103420004cdeb39edd03e2b"
+ "1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b842959"
+ "8c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
};
public void testEncodedPublicKey() throws Exception {
KeyFactory kf = KeyFactory.getInstance("EC");
for (String encodedHex : EC_INVALID_PUBLIC_KEYS) {
byte[] encoded = TestUtil.hexToBytes(encodedHex);
X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(encoded);
try {
ECPublicKey unused = (ECPublicKey) kf.generatePublic(x509keySpec);
fail("Constructed invalid public key from:" + encodedHex);
} catch (InvalidKeySpecException ex) {
// OK, since the public keys have been modified.
System.out.println(ex.toString());
}
}
}
public void testEncodedPrivateKey() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(EcUtil.getNistP256Params());
KeyPair keyPair = keyGen.generateKeyPair();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
byte[] encoded = priv.getEncoded();
System.out.println("Encoded ECPrivateKey:" + TestUtil.bytesToHex(encoded));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("EC");
ECPrivateKey decoded = (ECPrivateKey) kf.generatePrivate(spec);
assertEquals(priv.getS(), decoded.getS());
assertEquals(priv.getParams().getCofactor(), decoded.getParams().getCofactor());
assertEquals(priv.getParams().getCurve(), decoded.getParams().getCurve());
assertEquals(priv.getParams().getGenerator(), decoded.getParams().getGenerator());
assertEquals(priv.getParams().getOrder(), decoded.getParams().getOrder());
}
/**
* Tests key generation for given parameters. The test can be skipped if the curve is not a
* standard curve.
*/
void testKeyGeneration(ECParameterSpec ecParams, boolean isStandard) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
KeyPair keyPair;
try {
keyGen.initialize(ecParams);
keyPair = keyGen.generateKeyPair();
} catch (InvalidAlgorithmParameterException ex) {
if (!isStandard) {
return;
}
throw ex;
}
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
EcUtil.checkPublicKey(pub);
BigInteger s = priv.getS();
// Check the length of s. Could fail with probability 2^{-32}.
assertTrue(s.bitLength() >= EcUtil.fieldSizeInBits(ecParams.getCurve()) - 32);
// TODO(bleichen): correct curve?
// TODO(bleichen): use RandomUtil
}
public void testKeyGenerationAll() throws Exception {
testKeyGeneration(EcUtil.getNistP224Params(), true);
testKeyGeneration(EcUtil.getNistP256Params(), true);
testKeyGeneration(EcUtil.getNistP384Params(), true);
testKeyGeneration(EcUtil.getNistP521Params(), true);
// Curves that are sometimes not supported.
testKeyGeneration(EcUtil.getBrainpoolP256r1Params(), false);
}
/**
* Checks that the default key size for ECDSA is up to date.
* The test uses NIST SP 800-57 part1 revision 4, Table 2, page 53
* http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf
* for the minimal key size of EC keys.
* Nist recommends a minimal security strength of 112 bits for the time until 2030.
* To achieve this security strength EC keys of at least 224 bits are required.
*/
public void testDefaultKeyGeneration() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
KeyPair keyPair = keyGen.generateKeyPair();
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
int keySize = EcUtil.fieldSizeInBits(pub.getParams().getCurve());
if (keySize < 224) {
fail("Expected a default key size of at least 224 bits. Size of generate key is " + keySize);
}
}
/**
* Tries to generate a public key with a point at infinity. Public keys with a point at infinity
* should be rejected to prevent subgroup confinement attacks.
*/
public void testPublicKeyAtInfinity() throws Exception {
ECParameterSpec ecSpec = EcUtil.getNistP256Params();
try {
ECPublicKeySpec pubSpec = new ECPublicKeySpec(ECPoint.POINT_INFINITY, ecSpec);
fail(
"Point at infinity is not a valid public key. "
+ pubSpec.getW().equals(ECPoint.POINT_INFINITY));
} catch (java.lang.IllegalArgumentException ex) {
// This is expected
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,462 @@
/**
* @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.ProviderType;
import com.google.security.wycheproof.WycheproofRunner.SlowTest;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.util.Arrays;
import junit.framework.TestCase;
/**
* Tests ECDSA against invalid signatures.
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
// Tested providers:
// SunEC: accepts a few alternative encodings and throws run time exceptions.
// The implementation does not protect against timing attacks.
// BC: accepts alternative encoding, and additional arguments
// AndroidOpenSSL: OK
// TODO(bleichen):
// - CVE-2015-2730: Firefox failed to handle some signatures correctly because of incorrect
// point multiplication. (I don't have enough information here.)
public class EcdsaTest extends TestCase {
// ECDSA-Key1
static final String MESSAGE = "Hello";
static final String CURVE = "secp256r1";
static final BigInteger PubX =
new BigInteger(
"3390396496586153202365024500890309020181905168626402195853036609" + "0984128098564");
static final BigInteger PubY =
new BigInteger(
"1135421298983937257390683162600855221890652900790509030911087400" + "65052129055287");
// Valid signatures for MESSAGE
static final String[] VALID_SIGNATURES = {
"3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49"
+ "1b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285"
+ "cd59f43260ecce",
};
/**
* Test vectors with invalid signatures. The motivation for these test vectors are previously
* broken implementations. - The implementation of DSA in gpg4browsers accepted signatures with
* r=1 and s=q as valid. Similar bugs in ECDSA are thinkable, hence the test vectors contain a
* number of tests with edge case integers. - CVE-2013-2944: strongSwan 5.0.4 accepts invalid
* ECDSA signatures when openssl is used. (Not sure if the following interpretation is correct,
* because of missing details). OpenSSLs error codes are easy to misinterpret. For many functions
* the result can be 0 (verification failed), 1 (verification succeded) or -1 (invalid format). A
* simple if (result) { ... } will be incorrect in such situations. The test vectors below contain
* incorrectly encoded signatures. - careless ASN parsing. For example SunEC throws various run
* time exceptions when the ASN encoding is broken. NOTE(bleichen): The following test vectors
* were generated with some python code. New test vectors should best be done by extending this
* code.
*/
static final String[] INVALID_SIGNATURES = {
// missing argument
"30220220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f4" + "3260ecce",
"3023022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + "1b39fd2c3f",
"",
// empty
"302402000220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285cd" + "59f43260ecce",
"3025022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + "1b39fd2c3f0200",
"3000",
// integer overflows
"304a0285010000002100b7babae9332b54b8a3a05b7004579821a887a1b21465"
+ "f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c1"
+ "06a6e76285cd59f43260ecce",
"304e028901000000000000002100b7babae9332b54b8a3a05b7004579821a887"
+ "a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f"
+ "94e418c106a6e76285cd59f43260ecce",
"304a022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49"
+ "1b39fd2c3f02850100000020747291dd2f3f44af7ace68ea33431d6f94e418c1"
+ "06a6e76285cd59f43260ecce",
"304e022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49"
+ "1b39fd2c3f0289010000000000000020747291dd2f3f44af7ace68ea33431d6f"
+ "94e418c106a6e76285cd59f43260ecce",
"30850100000045022100b7babae9332b54b8a3a05b7004579821a887a1b21465"
+ "f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c1"
+ "06a6e76285cd59f43260ecce",
"3089010000000000000045022100b7babae9332b54b8a3a05b7004579821a887"
+ "a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f"
+ "94e418c106a6e76285cd59f43260ecce",
// infinity
"30250901800220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285" + "cd59f43260ecce",
"3026022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + "1b39fd2c3f090180",
// Signatures with special case values for r and s (such as 0 and 1).
// Such values often uncover implementation errors.
"300402000200",
"30050200020101",
"300502000201ff",
"30250200022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3" + "b9cac2fc632551",
"30250200022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3" + "b9cac2fc632550",
"30250200022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3" + "b9cac2fc632552",
"30250200022100ffffffff00000001000000000000000000000000ffffffffff" + "ffffffffffffff",
"30250200022100ffffffff000000010000000000000000000000010000000000" + "00000000000000",
"30070200090380fe01",
"30050201010200",
"3006020101020101",
"30060201010201ff",
"3026020101022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632551",
"3026020101022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632550",
"3026020101022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632552",
"3026020101022100ffffffff00000001000000000000000000000000ffffffff" + "ffffffffffffffff",
"3026020101022100ffffffff0000000100000000000000000000000100000000" + "0000000000000000",
"3008020101090380fe01",
"30050201ff0200",
"30060201ff020101",
"30060201ff0201ff",
"30260201ff022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632551",
"30260201ff022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632550",
"30260201ff022100ffffffff00000000ffffffffffffffffbce6faada7179e84" + "f3b9cac2fc632552",
"30260201ff022100ffffffff00000001000000000000000000000000ffffffff" + "ffffffffffffffff",
"30260201ff022100ffffffff0000000100000000000000000000000100000000" + "0000000000000000",
"30080201ff090380fe01",
"3025022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325510200",
"3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632551020101",
"3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325510201ff",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632551022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632551",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632551022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632550",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632551022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632552",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632551022100ffffffff00000001000000000000000000000000ffffffff"
+ "ffffffffffffffff",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632551022100ffffffff0000000100000000000000000000000100000000"
+ "0000000000000000",
"3028022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632551090380fe01",
"3025022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325500200",
"3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632550020101",
"3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325500201ff",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632550022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632551",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632550022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632550",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632550022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632552",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632550022100ffffffff00000001000000000000000000000000ffffffff"
+ "ffffffffffffffff",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632550022100ffffffff0000000100000000000000000000000100000000"
+ "0000000000000000",
"3028022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632550090380fe01",
"3025022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325520200",
"3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632552020101",
"3026022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc6325520201ff",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632552022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632551",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632552022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632550",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632552022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632552",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632552022100ffffffff00000001000000000000000000000000ffffffff"
+ "ffffffffffffffff",
"3046022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca"
+ "c2fc632552022100ffffffff0000000100000000000000000000000100000000"
+ "0000000000000000",
"3028022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9ca" + "c2fc632552090380fe01",
"3025022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff0200",
"3026022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff020101",
"3026022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff0201ff",
"3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ "ffffffffff022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632551",
"3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ "ffffffffff022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632550",
"3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ "ffffffffff022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632552",
"3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ "ffffffffff022100ffffffff00000001000000000000000000000000ffffffff"
+ "ffffffffffffffff",
"3046022100ffffffff00000001000000000000000000000000ffffffffffffff"
+ "ffffffffff022100ffffffff0000000100000000000000000000000100000000"
+ "0000000000000000",
"3028022100ffffffff00000001000000000000000000000000ffffffffffffff" + "ffffffffff090380fe01",
"3025022100ffffffff0000000100000000000000000000000100000000000000" + "00000000000200",
"3026022100ffffffff0000000100000000000000000000000100000000000000" + "0000000000020101",
"3026022100ffffffff0000000100000000000000000000000100000000000000" + "00000000000201ff",
"3046022100ffffffff0000000100000000000000000000000100000000000000"
+ "0000000000022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632551",
"3046022100ffffffff0000000100000000000000000000000100000000000000"
+ "0000000000022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632550",
"3046022100ffffffff0000000100000000000000000000000100000000000000"
+ "0000000000022100ffffffff00000000ffffffffffffffffbce6faada7179e84"
+ "f3b9cac2fc632552",
"3046022100ffffffff0000000100000000000000000000000100000000000000"
+ "0000000000022100ffffffff00000001000000000000000000000000ffffffff"
+ "ffffffffffffffff",
"3046022100ffffffff0000000100000000000000000000000100000000000000"
+ "0000000000022100ffffffff0000000100000000000000000000000100000000"
+ "0000000000000000",
"3028022100ffffffff0000000100000000000000000000000100000000000000" + "0000000000090380fe01",
};
/**
* Determines the Hash name from the ECDSA algorithm. There is a small inconsistency in the naming
* of algorithms. The Oracle standard use no hyphen in SHA256WithECDSA but uses a hyphen in the
* message digest, i.e., SHA-256.
*/
public String getHashAlgorithm(String ecdsaAlgorithm) {
ecdsaAlgorithm = ecdsaAlgorithm.toUpperCase();
int idx = ecdsaAlgorithm.indexOf("WITH");
if (idx > 0) {
if (ecdsaAlgorithm.startsWith("SHA")) {
return "SHA-" + ecdsaAlgorithm.substring(3, idx);
} else {
return ecdsaAlgorithm.substring(0, idx);
}
}
return "";
}
/**
* Extract the integer r from an ECDSA signature. This method implicitely assumes that the ECDSA
* signature is DER encoded. and that the order of the curve is smaller than 2^1024.
*/
BigInteger extractR(byte[] signature) throws Exception {
int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
int lengthR = signature[startR + 1];
return new BigInteger(Arrays.copyOfRange(signature, startR + 2, startR + 2 + lengthR));
}
BigInteger extractS(byte[] signature) throws Exception {
int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
int lengthR = signature[startR + 1];
int startS = startR + 2 + lengthR;
int lengthS = signature[startS + 1];
return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS));
}
/** Extract the k that was used to sign the signature. */
BigInteger extractK(byte[] signature, BigInteger h, ECPrivateKey priv) throws Exception {
BigInteger x = priv.getS();
BigInteger n = priv.getParams().getOrder();
BigInteger r = extractR(signature);
BigInteger s = extractS(signature);
BigInteger k = x.multiply(r).add(h).multiply(s.modInverse(n)).mod(n);
return k;
}
public ECPublicKeySpec publicKey1() throws Exception {
ECParameterSpec params = EcUtil.getNistP256Params();
ECPoint w = new ECPoint(PubX, PubY);
return new ECPublicKeySpec(w, params);
}
public void testVectors(
String[] signatures,
ECPublicKeySpec pubSpec,
String message,
String algorithm,
String signatureType,
boolean isValid)
throws Exception {
byte[] messageBytes = message.getBytes("UTF-8");
Signature verifier = Signature.getInstance(algorithm);
KeyFactory kf = KeyFactory.getInstance("EC");
ECPublicKey pub = (ECPublicKey) kf.generatePublic(pubSpec);
int errors = 0;
for (String signature : signatures) {
byte[] signatureBytes = TestUtil.hexToBytes(signature);
verifier.initVerify(pub);
verifier.update(messageBytes);
boolean verified = false;
try {
verified = verifier.verify(signatureBytes);
} catch (SignatureException ex) {
// verify can throw SignatureExceptions if the signature is malformed.
// We don't flag these cases and simply consider the signature as invalid.
verified = false;
}
//
if (isValid && !verified) {
System.out.println(signatureType + " was not verified:" + signature);
errors++;
} else if (!isValid && verified) {
System.out.println(signatureType + " was verified:" + signature);
errors++;
}
}
assertEquals(0, errors);
}
public void testValidSignatures() throws Exception {
testVectors(
VALID_SIGNATURES, publicKey1(), "Hello", "SHA256WithECDSA", "Valid ECDSA signature", true);
}
public void testInvalidSignatures() throws Exception {
testVectors(
INVALID_SIGNATURES,
publicKey1(),
"Hello",
"SHA256WithECDSA",
"Invalid ECDSA signature",
false);
}
/**
* This test checks the basic functionality of ECDSA. It can also be used to generate simple test
* vectors.
*/
public void testBasic() throws Exception {
String algorithm = "SHA256WithECDSA";
String hashAlgorithm = "SHA-256";
String message = "Hello";
String curve = "secp256r1";
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
keyGen.initialize(ecSpec);
KeyPair keyPair = keyGen.generateKeyPair();
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
byte[] messageBytes = message.getBytes("UTF-8");
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);
ECParameterSpec 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("Curve:" + curve);
System.out.println("Order:" + params.getOrder().toString());
System.out.println("Private key:");
System.out.println("S:" + priv.getS().toString());
System.out.println("encoded:" + TestUtil.bytesToHex(priv.getEncoded()));
System.out.println("Public key:");
ECPoint w = pub.getW();
System.out.println("X:" + w.getAffineX().toString());
System.out.println("Y:" + w.getAffineY().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());
}
/** Checks whether the one time key k in ECDSA is biased. */
public void testBias(String algorithm, String curve, ECParameterSpec ecParams) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
try {
keyGen.initialize(ecParams);
} catch (InvalidAlgorithmParameterException ex) {
System.out.println("This provider does not support curve:" + curve);
return;
}
KeyPair keyPair = keyGen.generateKeyPair();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
// If we throw a fair coin tests times then the probability that
// either heads or tails appears less than mincount is less than 2^{-32}.
// Therefore the test below is not expected to fail unless the generation
// of the one time keys is indeed biased.
final int tests = 1024;
final int mincount = 410;
String hashAlgorithm = getHashAlgorithm(algorithm);
String message = "Hello";
byte[] messageBytes = message.getBytes("UTF-8");
byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
// TODO(bleichen): Truncate the digest if the digest size is larger than the
// curve size.
BigInteger h = new BigInteger(1, digest);
BigInteger q = priv.getParams().getOrder();
BigInteger qHalf = q.shiftRight(1);
Signature signer = Signature.getInstance(algorithm);
signer.initSign(priv);
int countLsb = 0; // count the number of k's with msb set
int countMsb = 0; // count the number of k's with lsb set
for (int i = 0; i < tests; i++) {
signer.update(messageBytes);
byte[] signature = signer.sign();
BigInteger k = extractK(signature, h, priv);
if (k.testBit(0)) {
countLsb++;
}
if (k.compareTo(qHalf) == 1) {
countMsb++;
}
}
System.out.println(
signer.getProvider().getName()
+ " curve:"
+ curve
+ " countLsb:"
+ countLsb
+ " countMsb:"
+ countMsb);
if (countLsb < mincount || countLsb > tests - mincount) {
fail("Bias detected in the least significant bit of k:" + countLsb);
}
if (countMsb < mincount || countMsb > tests - mincount) {
fail("Bias detected in the most significant bit of k:" + countMsb);
}
}
@SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.CONSCRYPT, ProviderType.OPENJDK,
ProviderType.SPONGY_CASTLE})
public void testBiasAll() throws Exception {
testBias("SHA256WithECDSA", "secp256r1", EcUtil.getNistP256Params());
testBias("SHA224WithECDSA", "secp224r1", EcUtil.getNistP224Params());
testBias("SHA384WithECDSA", "secp384r1", EcUtil.getNistP384Params());
testBias("SHA512WithECDSA", "secp521r1", EcUtil.getNistP521Params());
testBias("SHA256WithECDSA", "brainpoolP256r1", EcUtil.getBrainpoolP256r1Params());
}
}
@@ -0,0 +1,347 @@
/**
* @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.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;
import java.util.HashSet;
import javax.crypto.Cipher;
import junit.framework.TestCase;
/**
* Testing ECIES.
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
// Tested providers:
// BouncyCastle v 1.52: IESCipher is amazingly buggy, both from a crypto
// viewpoint and from an engineering viewpoint. It uses encryption modes that are completely
// inapproriate for ECIES or DHIES (i.e. ECB), the CBC implementation distinguishes between
// padding and MAC failures allowing adaptive chosen-ciphertext attacks. The implementation
// allows to specify paddings, but ignores them, encryption using ByteBuffers doesn't even work
// without exceptions, indicating that this hasn't even tested.
//
// <p>TODO(bleichen):
// - compressed points,
// - maybe again CipherInputStream, CipherOutputStream,
// - BouncyCastle has a KeyPairGenerator for ECIES. Is this one different from EC?
public class EciesTest extends TestCase {
int expectedCiphertextLength(String algorithm, int coordinateSize, int messageLength)
throws Exception {
switch (algorithm.toUpperCase()) {
case "ECIESWITHAES-CBC":
// Uses the encoding
// 0x04 || coordinate x || coordinate y || PKCS5 padded ciphertext || 20-byte HMAC-digest.
return 1 + (2 * coordinateSize) + (messageLength - messageLength % 16 + 16) + 20;
default:
fail("Not implemented");
}
return -1;
}
/**
* Check that key agreement using ECIES works. This example does not specify an IESParametersSpec.
* BouncyCastle v.1.52 uses the following algorithms: KDF2 with SHA1 for the key derivation
* AES-CBC with PKCS #5 padding. HMAC-SHA1 with a 20 byte digest. The AES and the HMAC key are
* both 128 bits.
*/
@SuppressWarnings("InsecureCipherMode")
public void testEciesBasic() throws Exception {
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
PrivateKey priv = keyPair.getPrivate();
PublicKey pub = keyPair.getPublic();
byte[] message = "Hello".getBytes("UTF-8");
Cipher ecies = Cipher.getInstance("ECIESwithAES-CBC");
ecies.init(Cipher.ENCRYPT_MODE, pub);
byte[] ciphertext = ecies.doFinal(message);
System.out.println("testEciesBasic:" + TestUtil.bytesToHex(ciphertext));
ecies.init(Cipher.DECRYPT_MODE, priv);
byte[] decrypted = ecies.doFinal(ciphertext);
assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
}
/**
* ECIES does not allow encryption modes and paddings. If this test fails then we should add
* additional tests covering the new algorithms.
*/
// TODO(bleichen): This test describes BouncyCastles behaviour, but not necessarily what we
// expect.
@SuppressWarnings("InsecureCipherMode")
public void testInvalidNames() throws Exception {
String[] invalidNames =
new String[] {
"ECIESWITHAES/CBC/PKCS5PADDING",
"ECIESWITHAES/CBC/PKCS7PADDING",
"ECIESWITHAES/ECB/NOPADDING",
"ECIESWITHAES/CTR/NOPADDING",
};
for (String algorithm : invalidNames) {
try {
Cipher.getInstance(algorithm);
fail("unexpected algorithm:" + algorithm);
} catch (NoSuchAlgorithmException ex) {
// this is expected
}
}
}
/** Here are a few names that BouncyCastle accepts. */
// TODO(bleichen): This test describes BouncyCastles behaviour, but not necessarily what we
// expect.
@SuppressWarnings("InsecureCipherMode")
public void testValidNames() throws Exception {
String[] invalidNames =
new String[] {
"ECIESWITHAES/DHAES/NOPADDING",
"ECIES/DHAES/PKCS7PADDING",
"ECIESWITHDESEDE/DHAES/NOPADDING",
"ECIESWITHAES-CBC/NONE/NOPADDING",
};
for (String algorithm : invalidNames) {
Cipher.getInstance(algorithm);
}
}
/**
* BouncyCastle has a key generation algorithm "ECIES". This test checks that the result are
* ECKeys in both cases.
*/
public void testKeyGeneration() throws Exception {
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator kf = KeyPairGenerator.getInstance("ECIES");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
}
/**
* Check the length of the ciphertext. TODO(bleichen): This is more an explanation what is going
* on than a test. Maybe remove this later.
*/
@SuppressWarnings("InsecureCipherMode")
public void testCiphertextLength() throws Exception {
String algorithm = "ECIESwithAES-CBC";
final int messageLength = 40;
final int coordinateSize = 32;
byte[] message = new byte[messageLength];
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
PublicKey pub = keyPair.getPublic();
Cipher ecies = Cipher.getInstance(algorithm);
ecies.init(Cipher.ENCRYPT_MODE, pub);
byte[] ciphertext = ecies.doFinal(message);
assertEquals(
expectedCiphertextLength(algorithm, coordinateSize, messageLength), ciphertext.length);
}
// Tries to decrypt ciphertexts where the symmetric part has been
// randomized. Distinguishable exceptions mean that a padding attack
// may be possible.
@SuppressWarnings("InsecureCipherMode")
public void testExceptions(String algorithm) throws Exception {
Cipher ecies;
try {
ecies = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException ex) {
// Allowing to skip the algorithm
System.out.println("No implementation for:" + algorithm);
return;
}
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
final int kemSize = 65;
KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
PrivateKey priv = keyPair.getPrivate();
PublicKey pub = keyPair.getPublic();
byte[] message = new byte[40];
ecies.init(Cipher.ENCRYPT_MODE, pub);
byte[] ciphertext = ecies.doFinal(message);
System.out.println(TestUtil.bytesToHex(ciphertext));
ecies.init(Cipher.DECRYPT_MODE, priv);
HashSet<String> exceptions = new HashSet<String>();
for (int byteNr = kemSize; byteNr < ciphertext.length; byteNr++) {
for (int bit = 0; bit < 8; bit++) {
byte[] corrupt = Arrays.copyOf(ciphertext, ciphertext.length);
corrupt[byteNr] ^= (byte) (1 << bit);
ecies.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
try {
ecies.doFinal(corrupt);
fail("Decrypted:" + TestUtil.bytesToHex(corrupt));
} catch (Exception ex) {
String exception = ex.toString();
if (exceptions.add(exception)) {
System.out.println(algorithm + ":" + exception);
}
}
}
}
assertEquals(1, exceptions.size());
}
public void testEciesCorruptDefault() throws Exception {
testExceptions("ECIES");
}
@SuppressWarnings("InsecureCipherMode")
public void testModifyPoint() throws Exception {
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
PrivateKey priv = keyPair.getPrivate();
PublicKey pub = keyPair.getPublic();
byte[] message = "This is a long text since we need 32 bytes.".getBytes("UTF-8");
Cipher ecies = Cipher.getInstance("ECIESwithAES-CBC");
ecies.init(Cipher.ENCRYPT_MODE, pub);
byte[] ciphertext = ecies.doFinal(message);
ciphertext[2] ^= (byte) 1;
ecies.init(Cipher.DECRYPT_MODE, priv);
try {
ecies.doFinal(ciphertext);
fail("This should not work");
} catch (java.lang.IllegalArgumentException ex) {
// This is what BouncyCastle throws when the points are not on the curve.
// Maybe GeneralSecurityException would be better.
}
}
/**
* This test tries to detect ECIES implementations using ECB. This is insecure and also violates
* the claims of ECIES, since ECIES is secure agains adaptive chosen-ciphertext attacks.
*/
@SuppressWarnings("InsecureCipherMode")
public void testNotEcb(String algorithm) throws Exception {
Cipher ecies;
try {
ecies = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException ex) {
// This test is called with short algorithm names such as just "ECIES".
// Requiring full names is typically a good practice. Hence it is OK
// to not assigning default algorithms.
System.out.println("No implementation for:" + algorithm);
return;
}
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
PublicKey pub = keyPair.getPublic();
byte[] message = new byte[512];
ecies.init(Cipher.ENCRYPT_MODE, pub);
byte[] ciphertext = ecies.doFinal(message);
String block1 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, 241, 257));
String block2 = TestUtil.bytesToHex(Arrays.copyOfRange(ciphertext, 257, 273));
assertTrue("Ciphertext repeats:" + TestUtil.bytesToHex(ciphertext), !block1.equals(block2));
}
public void testDefaultEcies() throws Exception {
testNotEcb("ECIES");
}
/**
* Tests whether algorithmA is an alias of algorithmB by encrypting with algorithmA and decrypting
* with algorithmB.
*/
@SuppressWarnings("InsecureCipherMode")
public void testIsAlias(String algorithmA, String algorithmB) throws Exception {
Cipher eciesA;
Cipher eciesB;
// Allowing tests to be skipped, because we don't want to encourage abbreviations.
try {
eciesA = Cipher.getInstance(algorithmA);
} catch (NoSuchAlgorithmException ex) {
System.out.println("Skipping because of:" + ex.toString());
return;
}
try {
eciesB = Cipher.getInstance(algorithmB);
} catch (NoSuchAlgorithmException ex) {
System.out.println("Skipping because of:" + ex.toString());
return;
}
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
byte[] message = "Hello".getBytes("UTF-8");
eciesA.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] ciphertext = eciesA.doFinal(message);
eciesB.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] decrypted = eciesB.doFinal(ciphertext);
assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
}
/** Tests whether two distinct algorithm names implement the same cipher */
public void testAlias() throws Exception {
testIsAlias("ECIESWITHAES-CBC", "ECIESWithAES-CBC");
testIsAlias("ECIESWITHAES", "ECIESWithAES");
// BouncyCastle v 1.52 ignores mode and padding and considers the following
// names as equivalent:
// testIsAlias("ECIES/DHAES/PKCS7PADDING", "ECIES");
testIsAlias("ECIESWITHAES-CBC/NONE/PKCS7PADDING", "ECIESWITHAES-CBC/NONE/NOPADDING");
}
/**
* Cipher.doFinal(ByteBuffer, ByteBuffer) should be copy-safe according to
* https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
*
* <p>This test tries to verify this.
*/
/* TODO(bleichen): There's no point to run this test as long as not even the previous basic
test fails.
public void testByteBufferAlias() throws Exception {
byte[] message = "Hello".getBytes("UTF-8");
String algorithm = "ECIESWithAES-CBC";
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator kf = KeyPairGenerator.getInstance("EC");
kf.initialize(ecSpec);
KeyPair keyPair = kf.generateKeyPair();
Cipher ecies = Cipher.getInstance(algorithm);
int ciphertextLength = expectedCiphertextLength(algorithm, 32, message.length);
byte[] backingArray = new byte[ciphertextLength];
ByteBuffer ptBuffer = ByteBuffer.wrap(backingArray);
ptBuffer.put(message);
ptBuffer.flip();
ecies.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
ByteBuffer ctBuffer = ByteBuffer.wrap(backingArray);
ecies.doFinal(ptBuffer, ctBuffer);
ctBuffer.flip();
ecies.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] decrypted = ecies.doFinal(backingArray, 0, ctBuffer.remaining());
assertEquals(TestUtil.bytesToHex(message), TestUtil.bytesToHex(decrypted));
}
*/
}
@@ -0,0 +1,138 @@
/**
* @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.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashSet;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import junit.framework.TestCase;
/**
* RSA encryption tests
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
// TODO(bleichen): test vectors check special cases:
// - ciphertext too long
// - plaintext too long
// - ciphertext 0
// - ciphertext == modulus timing attacks
public class RsaEncryptionTest extends TestCase {
/**
* Providers that implement RSA with PKCS1Padding but not OAEP are outdated and should be avoided
* even if RSA is currently not used in a project. Such providers promote using an insecure
* cipher. There is a great danger that PKCS1Padding is used as a temporary workaround, but later
* stays in the project for much longer than necessary.
*/
public void testOutdatedProvider() throws Exception {
try {
Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
try {
Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
} catch (NoSuchPaddingException | NoSuchAlgorithmException ex) {
fail("Provider " + c.getProvider().getName() + " is outdated and should not be used.");
}
} catch (NoSuchPaddingException | NoSuchAlgorithmException ex) {
System.out.println("RSA/ECB/PKCS1Padding is not implemented");
}
}
/**
* Tries decrypting random messages with a given algorithm. Counts the number of distinct error
* messages and expects this number to be 1.
*
* <p><b>References:</b>
*
* <ul>
* <li>Bleichenbacher, "Chosen ciphertext attacks against protocols based on the RSA encryption
* standard PKCS# 1" Crypto 98
* <li>Manger, "A chosen ciphertext attack on RSA optimal asymmetric encryption padding (OAEP)
* as standardized in PKCS# 1 v2.0", Crypto 2001 This paper shows that OAEP is susceptible
* to a chosen ciphertext attack if error messages distinguish between different failure
* condidtions.
* <li>Bardou, Focardi, Kawamoto, Simionato, Steel, Tsay "Efficient Padding Oracle Attacks on
* Cryptographic Hardware", Crypto 2012 The paper shows that small differences on what
* information an attacker recieves can make a big difference on the number of chosen
* message necessary for an attack.
* <li>Smart, "Errors matter: Breaking RSA-based PIN encryption with thirty ciphertext validity
* queries" RSA conference, 2010 This paper shows that padding oracle attacks can be
* successful with even a small number of queries.
* </ul>
*
* <p><b>Some recent bugs:</b> CVE-2012-5081: Java JSSE provider leaked information through
* exceptions and timing. Both the PKCS #1 padding and the OAEP padding were broken:
* http://www-brs.ub.ruhr-uni-bochum.de/netahtml/HSS/Diss/MeyerChristopher/diss.pdf
*
* <p><b>What this test does not (yet) cover:</b>
*
* <ul>
* <li> A previous version of one of the provider leaked the block type. (when was this fixed?)
* <li> Some attacks require a large number of ciphertexts to be detected if random ciphertexts
* are used. Such problems require specifically crafted ciphertexts to run in a unit test.
* E.g. "Attacking RSA-based Sessions in SSL/TLS" by V. Klima, O. Pokorny, and T. Rosa:
* https://eprint.iacr.org/2003/052/
* <li> Timing leakages because of differences in parsing the padding (e.g. CVE-2015-7827) Such
* differences are too small to be reliably detectable in unit tests.
* </ul>
*/
@SuppressWarnings("InsecureCipherMode")
public void testExceptions(String algorithm) throws Exception {
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
keygen.initialize(1024);
KeyPair keypair = keygen.genKeyPair();
SecureRandom rand = new SecureRandom();
Cipher c = Cipher.getInstance(algorithm);
byte[] ciphertext = new byte[1024 / 8];
HashSet<String> exceptions = new HashSet<String>();
final int samples = 1000;
for (int i = 0; i < samples; i++) {
rand.nextBytes(ciphertext);
ciphertext[0] &= (byte) 0x7f;
try {
c.init(Cipher.DECRYPT_MODE, keypair.getPrivate());
c.doFinal(ciphertext);
} catch (Exception ex) {
exceptions.add(ex.toString());
}
}
if (exceptions.size() > 1) {
System.out.println("Exceptions for " + algorithm);
for (String s : exceptions) {
System.out.println(s);
}
fail("Exceptions leak information about the padding for " + algorithm);
}
}
/**
* Tests the exceptions for RSA decryption with PKCS1Padding. PKCS1Padding is susceptible to
* chosen message attacks. Nonetheless, to minimize the damage of such an attack an implementation
* should minimize the information about the failure in the padding.
*/
public void testExceptionsPKCS1() throws Exception {
testExceptions("RSA/ECB/PKCS1PADDING");
}
public void testGetExceptionsOAEP() throws Exception {
testExceptions("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
}
}
@@ -0,0 +1,139 @@
/**
* @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.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import junit.framework.TestCase;
/**
* Tests RSA keys. Signatures and encryption are tested in different tests.
*
* @author bleichen@google.com (Daniel Bleichenbacher)
*/
// TODO(bleichen):
// - Add checks for bad random numbers
// - expect keys with e=1 to be rejected
// - expect keys with e=0 to be rejected
// - document stuff
// - Maybe also check encodings of private keys.
// - Test multi prime RSA
// - Tests for alternative representations:
// many libraries sort the primes as: p > q (but not all)
// some libraries compute d mod lambda(n)
// paramaters p,q,... are not really required
// - checks for bad random number generation
public class RsaKeyTest extends TestCase {
public static final String ENCODED_PUBLIC_KEY =
"30819f300d06092a864886f70d010101050003818d0030818902818100ab9014"
+ "dc47d44b6d260fc1fef9ab022042fd9566e9d7b60c54100cb6e1d4edc9859046"
+ "7d0502c17fce69d00ac5efb40b2cb167d8a44ab93d73c4d0f109fb5a26c2f882"
+ "3236ff517cf84412e173679cfae42e043b6fec81f9d984b562517e6febe1f722"
+ "95dbc3fdfc19d3240aa75515563f31dad83563f3a315acf9a0b351a23f020301"
+ "0001";
private void checkPrivateCrtKey(RSAPrivateCrtKey key, int expectedKeySize) throws Exception {
BigInteger p = key.getPrimeP();
BigInteger q = key.getPrimeQ();
BigInteger n = key.getModulus();
BigInteger e = key.getPublicExponent();
BigInteger d = key.getPrivateExponent();
BigInteger dp = key.getPrimeExponentP();
BigInteger dq = key.getPrimeExponentQ();
BigInteger crtCoeff = key.getCrtCoefficient();
// Simple test that (n,d,e) is a valid RSA key.
assertEquals(n, p.multiply(q));
assertEquals(expectedKeySize, n.bitLength());
int certainty = 80;
assertTrue(p.isProbablePrime(certainty));
assertTrue(q.isProbablePrime(certainty));
// Very simple checks for weak random number generators.
RandomUtil.checkPrime(p);
RandomUtil.checkPrime(q);
assertTrue(d.bitLength() > expectedKeySize / 2);
// TODO(bleichen): Keys that are very imbalanced can be broken with elliptic curve factoring.
// Add other checks. E.g. for the size of dp and dq
assertTrue(p.bitLength() > 256);
assertTrue(q.bitLength() > 256);
BigInteger p1 = p.subtract(BigInteger.ONE);
BigInteger q1 = q.subtract(BigInteger.ONE);
BigInteger phi = p1.multiply(q1);
BigInteger order = phi.divide(p1.gcd(q1)); // maximal order of elements
assertEquals(BigInteger.ONE, d.multiply(e).mod(order));
assertEquals(d.mod(p1), dp.mod(p1));
assertEquals(d.mod(q1), dq.mod(q1));
assertEquals(q.multiply(crtCoeff).mod(p), BigInteger.ONE);
}
private void checkPublicKey(RSAPublicKey pub, RSAPrivateKey priv) {
assertEquals(pub.getModulus(), priv.getModulus());
BigInteger e = pub.getPublicExponent();
// Checks that e > 1. [CVE-1999-1444]
assertEquals(e.compareTo(BigInteger.ONE), 1);
}
private void checkKeyPair(KeyPair keypair, int keySizeInBits) throws Exception {
RSAPublicKey pub = (RSAPublicKey) keypair.getPublic();
RSAPrivateKey priv = (RSAPrivateKey) keypair.getPrivate();
if (priv instanceof RSAPrivateCrtKey) {
checkPrivateCrtKey((RSAPrivateCrtKey) priv, keySizeInBits);
} else {
// Using a CRT key leads to 6-7 times better performance than not using the CRT.
// Such a perfomance loss makes a library almost useless. Thus we consider this
// a bug.
fail("Expecting an RSAPrivateCrtKey instead of " + priv.getClass().getName());
}
checkPublicKey(pub, priv);
}
public void testKeyGenerationSize(int keySizeInBits) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(keySizeInBits);
KeyPair keypair = keyGen.genKeyPair();
checkKeyPair(keypair, keySizeInBits);
}
public void testKeyGeneration() throws Exception {
testKeyGenerationSize(1024);
testKeyGenerationSize(2048);
}
/**
* Checks whether decoding and again encoding an RSA public key results
* in the same encoding.
* This is a regression test. Failing this test implies that the encoding has changed.
* Such a failure does not need to be a bug, since several encoding for the same key are
* possible.
*/
public void testEncodeDecodePublic() throws Exception {
KeyFactory kf = KeyFactory.getInstance("RSA");
byte[] encoded = TestUtil.hexToBytes(ENCODED_PUBLIC_KEY);
X509EncodedKeySpec spec = new X509EncodedKeySpec(encoded);
RSAPublicKey pub = (RSAPublicKey) kf.generatePublic(spec);
assertEquals("The test assumes that the public key is in X.509 format",
"X.509", pub.getFormat());
assertEquals(ENCODED_PUBLIC_KEY, TestUtil.bytesToHex(pub.getEncoded()));
}
}
@@ -0,0 +1,140 @@
/**
* @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.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import junit.framework.TestCase;
/** Tests RSA signature schemes. */
// TODO(bleichen):
// - maybe add tests with invalid keys.
// - So far only PKCS #1 signatures are tested. But RSA-PSS becomes more popular.
// - document stuff
// - Join other RSA tests
public class RsaSignatureTest extends TestCase {
static final RSAPublicKeySpec RSA_KEY1 =
new RSAPublicKeySpec(
new BigInteger(
"ab9014dc47d44b6d260fc1fef9ab022042fd9566e9d7b60c54100cb6e1d4edc9"
+ "8590467d0502c17fce69d00ac5efb40b2cb167d8a44ab93d73c4d0f109fb5a26"
+ "c2f8823236ff517cf84412e173679cfae42e043b6fec81f9d984b562517e6feb"
+ "e1f72295dbc3fdfc19d3240aa75515563f31dad83563f3a315acf9a0b351a23f",
16),
new BigInteger("65537"));
static final String ALGORITHM_KEY1 = "SHA256WithRSA";
public void testBasic() throws Exception {
String algorithm = "SHA256WithRSA";
String hashAlgorithm = "SHA-256";
String message = "Hello";
int keysize = 2048;
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(keysize);
KeyPair keyPair = keyGen.generateKeyPair();
RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
byte[] messageBytes = message.getBytes("UTF-8");
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);
// 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("Public key:");
System.out.println("Modulus:" + pub.getModulus().toString());
System.out.println("E:" + pub.getPublicExponent().toString());
System.out.println("encoded:" + TestUtil.bytesToHex(pub.getEncoded()));
System.out.println("Private key:");
System.out.println("D:" + priv.getPrivateExponent().toString());
System.out.println("encoded:" + TestUtil.bytesToHex(priv.getEncoded()));
System.out.println("Signature:" + TestUtil.bytesToHex(signature));
}
/**
* Signatures with legacy encoding. Such signatures are sometimes accepted to be compatible with
* previously buggy implementations.
*/
static final String[] LEGACY_SIGNATURES_KEY1 = {
// A signature where the NULL parameter is missing in the ASN encoding.
// padding = 302f300b06096086480165030402010420532eaabd9574880dbf
// 76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25
"253e1d19bbe91064f2364c1e7db3ba8eb6dc5b19202e440eab6fbdf28c8c6ec0"
+ "5b812983713c338c72b6e99b8edf506a89ff9fc8e5c2c52362097a56dc228060"
+ "eca01e1ff318c6c81617691438703411c1f953b21cd74331f87c9b8b189fdffd"
+ "fe8550bd2bd1d47be915f8604a0f472199dd705e19b1b815f99b68d60bc257c7",
};
/**
* Tests legacy signatures. In this context we use the term legacy signatures for signatures that
* are not conforming to the PKCS #1 standard, but are sometimes generated by buggy signers. So
* far this test considers both accepting and rejecting such signatures as valid behavior.
*
* <p>Currently we check for just one type of legacy signatures: i.e., a missing NULL parameter in
* the ASN encoding of the hash. BouncyCastle and the SunJCE accept this signature, Conscrypt does
* not.
*
* <p>Some references that support accepting this signature:
* https://codereview.chromium.org/1690123002/
* https://groups.google.com/a/chromium.org/forum/#!topic/chromium-reviews/Jo5S7HtEABI claims that
* 7% of the responses in the Online Certificate Status Protocol (OCSP) miss the NULL parameter
*/
public void testLegacySignatures() throws Exception {
RSAPublicKeySpec key = RSA_KEY1;
String algorithm = ALGORITHM_KEY1;
byte[] message = "Test".getBytes("UTF-8");
Signature verifier = Signature.getInstance(algorithm);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub = kf.generatePublic(key);
for (String signature : LEGACY_SIGNATURES_KEY1) {
byte[] signatureBytes = TestUtil.hexToBytes(signature);
verifier.initVerify(pub);
verifier.update(message);
boolean verified = false;
try {
verified = verifier.verify(signatureBytes);
} catch (SignatureException ex) {
verified = false;
}
if (verified) {
System.out.println("Verfied legacy signature:" + signature);
} else {
System.out.println("Rejected legacy signature:" + signature);
}
}
}
}