use of java.security.interfaces.ECPrivateKey in project wycheproof by google.
the class EcdsaTest method testBias.
/** 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);
// count the number of k's with msb set
int countLsb = 0;
// count the number of k's with lsb set
int countMsb = 0;
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);
}
}
use of java.security.interfaces.ECPrivateKey in project wycheproof by google.
the class EcKeyTest method testKeyGeneration.
/**
* 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
}
use of java.security.interfaces.ECPrivateKey in project wycheproof by google.
the class EcdhTest method testModifiedPublicSpec.
/**
* This is a similar test as testModifiedPublic. However, this test uses test vectors
* ECPublicKeySpec
*/
@SuppressWarnings("InsecureCryptoUsage")
public void testModifiedPublicSpec(String algorithm) throws Exception {
KeyAgreement ka;
try {
ka = KeyAgreement.getInstance(algorithm);
} catch (NoSuchAlgorithmException ex) {
System.out.println("testWrongOrder: " + algorithm + " not supported");
return;
}
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(EcUtil.getNistP256Params());
ECPrivateKey priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
KeyFactory kf = KeyFactory.getInstance("EC");
ECPublicKey validKey = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getSpec());
ka.init(priv);
ka.doPhase(validKey, true);
String expected = TestUtil.bytesToHex(ka.generateSecret());
for (EcPublicKeyTestVector test : EC_MODIFIED_PUBLIC_KEYS) {
ECPublicKeySpec spec = test.getSpec();
if (spec == null) {
// spec == null if one of these validity checks fails. Of course such a failure is OK.
continue;
}
try {
ECPublicKey modifiedKey = (ECPublicKey) kf.generatePublic(spec);
ka.init(priv);
ka.doPhase(modifiedKey, true);
String shared = TestUtil.bytesToHex(ka.generateSecret());
// The implementation did not notice that the public key was modified.
// This is not nice, but at the moment we only fail the test if the
// modification was essential for computing the shared secret.
//
// BouncyCastle v.1.53 fails this test, for ECDHC with modified order.
// This implementation reduces the product s*h modulo the order given
// in the public key. An attacker who can modify the order of the public key
// and who can learn whether such a modification changes the shared secret is
// able to learn the private key with a simple binary search.
assertEquals("algorithm:" + algorithm + " test:" + test.comment, expected, shared);
} catch (GeneralSecurityException ex) {
// OK, since the public keys have been modified.
System.out.println("testModifiedPublic:" + test.comment + " throws " + ex.toString());
}
}
}
use of java.security.interfaces.ECPrivateKey in project wycheproof by google.
the class EcdhTest method testModifiedPublic.
/**
* This test modifies the order of group in the public key. A severe bug would be an
* implementation that leaks information whether the private key is larger than the order given in
* the public key. Also a severe bug would be to reduce the private key modulo the order given in
* the public key parameters.
*/
@SuppressWarnings("InsecureCryptoUsage")
public void testModifiedPublic(String algorithm) throws Exception {
KeyAgreement ka;
try {
ka = KeyAgreement.getInstance(algorithm);
} catch (NoSuchAlgorithmException ex) {
System.out.println("testWrongOrder: " + algorithm + " not supported");
return;
}
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(EcUtil.getNistP256Params());
ECPrivateKey priv = (ECPrivateKey) keyGen.generateKeyPair().getPrivate();
KeyFactory kf = KeyFactory.getInstance("EC");
ECPublicKey validKey = (ECPublicKey) kf.generatePublic(EC_VALID_PUBLIC_KEY.getSpec());
ka.init(priv);
ka.doPhase(validKey, true);
String expected = TestUtil.bytesToHex(ka.generateSecret());
for (EcPublicKeyTestVector test : EC_MODIFIED_PUBLIC_KEYS) {
try {
X509EncodedKeySpec spec = test.getX509EncodedKeySpec();
ECPublicKey modifiedKey = (ECPublicKey) kf.generatePublic(spec);
ka.init(priv);
ka.doPhase(modifiedKey, true);
String shared = TestUtil.bytesToHex(ka.generateSecret());
// The implementation did not notice that the public key was modified.
// This is not nice, but at the moment we only fail the test if the
// modification was essential for computing the shared secret.
//
// BouncyCastle v.1.53 fails this test, for ECDHC with modified order.
// This implementation reduces the product s*h modulo the order given
// in the public key. An attacker who can modify the order of the public key
// and who can learn whether such a modification changes the shared secret is
// able to learn the private key with a simple binary search.
assertEquals("algorithm:" + algorithm + " test:" + test.comment, expected, shared);
} catch (GeneralSecurityException ex) {
// OK, since the public keys have been modified.
System.out.println("testModifiedPublic:" + test.comment + " throws " + ex.toString());
}
}
}
use of java.security.interfaces.ECPrivateKey in project wycheproof by google.
the class EcdsaTest method testTiming.
/**
* Tests for a potential timing attack. This test checks if there is a correlation between the
* timing of signature generation and the size of the one-time key k. This is for example the case
* if a double and add method is used for the point multiplication. The test fails if such a
* correlation can be shown with high confidence. Further analysis will be necessary to determine
* how easy it is to exploit the bias in a timing attack.
*/
// TODO(bleichen): Determine if there are exploitable providers.
//
// SunEC currently fails this test. Since ECDSA typically is used with EC groups whose order
// is 224 bits or larger, it is unclear whether the same attacks that apply to DSA are practical.
//
// The ECDSA implementation in BouncyCastle leaks information about k through timing too.
// The test has not been optimized to detect this bias. It would require about 5'000'000 samples,
// which is too much for a simple unit test.
//
// BouncyCastle uses FixedPointCombMultiplier for ECDSA. This is a method using
// precomputation. The implementation is not constant time, since the precomputation table
// contains the point at infinity and adding this point is faster than ordinary point additions.
// The timing leak only has a small correlation to the size of k and at the moment it is is very
// unclear if the can be exploited. (Randomizing the precomputation table by adding the same
// random point to each element in the table and precomputing the necessary offset to undo the
// precomputation seems much easier than analyzing this.)
public void testTiming(String algorithm, String curve, ECParameterSpec ecParams) throws Exception {
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
if (!bean.isCurrentThreadCpuTimeSupported()) {
System.out.println("getCurrentThreadCpuTime is not supported. Skipping");
return;
}
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();
String message = "Hello";
String hashAlgorithm = getHashAlgorithm(algorithm);
byte[] messageBytes = message.getBytes("UTF-8");
byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
BigInteger h = new BigInteger(1, digest);
Signature signer = Signature.getInstance(algorithm);
signer.initSign(priv);
// The number of samples used for the test. This number is a bit low.
// I.e. it just barely detects that SunEC leaks information about the size of k.
int samples = 50000;
long[] timing = new long[samples];
BigInteger[] k = new BigInteger[samples];
for (int i = 0; i < samples; i++) {
long start = bean.getCurrentThreadCpuTime();
signer.update(messageBytes);
byte[] signature = signer.sign();
timing[i] = bean.getCurrentThreadCpuTime() - start;
k[i] = extractK(signature, h, priv);
}
long[] sorted = Arrays.copyOf(timing, timing.length);
Arrays.sort(sorted);
double n = priv.getParams().getOrder().doubleValue();
double expectedAverage = n / 2;
double maxSigma = 0;
System.out.println("testTiming algorithm:" + algorithm);
for (int idx = samples - 1; idx > 10; idx /= 2) {
long cutoff = sorted[idx];
int count = 0;
BigInteger total = BigInteger.ZERO;
for (int i = 0; i < samples; i++) {
if (timing[i] <= cutoff) {
total = total.add(k[i]);
count += 1;
}
}
double expectedStdDev = n / Math.sqrt(12 * count);
double average = total.doubleValue() / count;
// Number of standard deviations that the average is away from
// the expected value:
double sigmas = (expectedAverage - average) / expectedStdDev;
if (sigmas > maxSigma) {
maxSigma = sigmas;
}
System.out.println("count:" + count + " cutoff:" + cutoff + " relative average:" + (average / expectedAverage) + " sigmas:" + sigmas);
}
// than 10^{-10}.
if (maxSigma >= 7) {
fail("Signatures with short timing have a biased k");
}
}
Aggregations