Initial GitHub export
This commit is contained in:
committed by
Thai Duong
parent
c662a0ac90
commit
f7ecb0dfad
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user