use of java.security.interfaces.DSAPrivateKey in project jruby-openssl by jruby.
the class PKeyDSA method initialize.
@JRubyMethod(rest = true, visibility = Visibility.PRIVATE)
public IRubyObject initialize(final ThreadContext context, final IRubyObject[] args) {
final Ruby runtime = context.runtime;
if (Arity.checkArgumentCount(runtime, args, 0, 2) == 0) {
this.privateKey = null;
this.publicKey = null;
return this;
}
IRubyObject arg = args[0];
IRubyObject pass = null;
if (args.length > 1)
pass = args[1];
if (arg instanceof RubyFixnum) {
int keySize = RubyNumeric.fix2int((RubyFixnum) arg);
return dsaGenerate(context.runtime, this, keySize);
}
final char[] passwd = password(pass);
final RubyString str = readInitArg(context, arg);
final String strJava = str.toString();
Object key = null;
final KeyFactory dsaFactory;
try {
dsaFactory = SecurityHelper.getKeyFactory("DSA");
} catch (NoSuchAlgorithmException e) {
throw runtime.newRuntimeError("unsupported key algorithm (DSA)");
} catch (RuntimeException e) {
throw runtime.newRuntimeError("unsupported key algorithm (DSA) " + e);
}
// TODO: ugly NoClassDefFoundError catching for no BC env. How can we remove this?
boolean noClassDef = false;
if (key == null && !noClassDef) {
// PEM_read_bio_DSAPrivateKey
try {
key = readPrivateKey(strJava, passwd);
} catch (NoClassDefFoundError e) {
noClassDef = true;
debugStackTrace(runtime, e);
} catch (PEMInputOutput.PasswordRequiredException retry) {
if (ttySTDIN(context)) {
try {
key = readPrivateKey(strJava, passwordPrompt(context));
} catch (Exception e) {
debugStackTrace(runtime, e);
}
}
} catch (Exception e) {
debugStackTrace(runtime, e);
}
}
if (key == null && !noClassDef) {
// PEM_read_bio_DSAPublicKey
try {
key = PEMInputOutput.readDSAPublicKey(new StringReader(strJava), passwd);
} catch (NoClassDefFoundError e) {
noClassDef = true;
debugStackTrace(runtime, e);
} catch (Exception e) {
debugStackTrace(runtime, e);
}
}
if (key == null && !noClassDef) {
// PEM_read_bio_DSA_PUBKEY
try {
key = PEMInputOutput.readDSAPubKey(new StringReader(strJava));
} catch (NoClassDefFoundError e) {
noClassDef = true;
debugStackTrace(runtime, e);
} catch (Exception e) {
debugStackTrace(runtime, e);
}
}
if (key == null && !noClassDef) {
// d2i_DSAPrivateKey_bio
try {
key = readDSAPrivateKey(dsaFactory, str.getBytes());
} catch (NoClassDefFoundError e) {
noClassDef = true;
debugStackTrace(runtime, e);
} catch (InvalidKeySpecException e) {
debug(runtime, "PKeyDSA could not read private key", e);
} catch (IOException e) {
debug(runtime, "PKeyDSA could not read private key", e);
} catch (RuntimeException e) {
if (isKeyGenerationFailure(e))
debug(runtime, "PKeyDSA could not read private key", e);
else
debugStackTrace(runtime, e);
}
}
if (key == null && !noClassDef) {
// d2i_DSA_PUBKEY_bio
try {
key = readDSAPublicKey(dsaFactory, str.getBytes());
} catch (NoClassDefFoundError e) {
noClassDef = true;
debugStackTrace(runtime, e);
} catch (InvalidKeySpecException e) {
debug(runtime, "PKeyDSA could not read public key", e);
} catch (IOException e) {
debug(runtime, "PKeyDSA could not read public key", e);
} catch (RuntimeException e) {
if (isKeyGenerationFailure(e))
debug(runtime, "PKeyDSA could not read public key", e);
else
debugStackTrace(runtime, e);
}
}
if (key == null)
key = tryPKCS8EncodedKey(runtime, dsaFactory, str.getBytes());
if (key == null)
key = tryX509EncodedKey(runtime, dsaFactory, str.getBytes());
if (key == null)
throw newDSAError(runtime, "Neither PUB key nor PRIV key:");
if (key instanceof KeyPair) {
final PublicKey pubKey = ((KeyPair) key).getPublic();
final PrivateKey privKey = ((KeyPair) key).getPrivate();
if (!(privKey instanceof DSAPrivateKey)) {
if (privKey == null) {
throw newDSAError(runtime, "Neither PUB key nor PRIV key: (private key is null)");
}
throw newDSAError(runtime, "Neither PUB key nor PRIV key: (invalid key type " + privKey.getClass().getName() + ")");
}
this.privateKey = (DSAPrivateKey) privKey;
this.publicKey = (DSAPublicKey) pubKey;
} else if (key instanceof DSAPrivateKey) {
this.privateKey = (DSAPrivateKey) key;
} else if (key instanceof DSAPublicKey) {
this.publicKey = (DSAPublicKey) key;
this.privateKey = null;
} else {
throw newDSAError(runtime, "Neither PUB key nor PRIV key: " + key.getClass().getName());
}
return this;
}
use of java.security.interfaces.DSAPrivateKey in project Zom-Android by zom.
the class OtrCryptoEngineImpl method sign.
public byte[] sign(byte[] b, PrivateKey privatekey) throws OtrCryptoException {
if (!(privatekey instanceof DSAPrivateKey))
throw new IllegalArgumentException();
DSAParams dsaParams = ((DSAPrivateKey) privatekey).getParams();
DSAParameters bcDSAParameters = new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privatekey;
DSAPrivateKeyParameters bcDSAPrivateKeyParms = new DSAPrivateKeyParameters(dsaPrivateKey.getX(), bcDSAParameters);
DSASigner dsaSigner = new DSASigner();
dsaSigner.init(true, bcDSAPrivateKeyParms);
BigInteger q = dsaParams.getQ();
// Ian: Note that if you can get the standard DSA implementation you're
// using to not hash its input, you should be able to pass it ((256-bit
// value) mod q), (rather than truncating the 256-bit value) and all
// should be well.
// ref: Interop problems with libotr - DSA signature
BigInteger bmpi = new BigInteger(1, b);
BigInteger[] rs = dsaSigner.generateSignature(BigIntegers.asUnsignedByteArray(bmpi.mod(q)));
int siglen = q.bitLength() / 4;
int rslen = siglen / 2;
byte[] rb = BigIntegers.asUnsignedByteArray(rs[0]);
byte[] sb = BigIntegers.asUnsignedByteArray(rs[1]);
// Create the final signature array, padded with zeros if necessary.
byte[] sig = new byte[siglen];
Boolean writeR = false;
Boolean writeS = false;
int shiftR = rslen - rb.length;
int shiftS = rslen - sb.length;
for (int i = 0; i < siglen; i++) {
if (i < rslen) {
if (!writeR)
writeR = rb.length >= rslen - i;
sig[i] = (writeR) ? rb[i - shiftR] : (byte) 0x0;
} else {
// Rebase.
int j = i - rslen;
if (!writeS)
writeS = sb.length >= rslen - j;
sig[i] = (writeS) ? sb[j - shiftS] : (byte) 0x0;
}
}
return sig;
}
use of java.security.interfaces.DSAPrivateKey in project wycheproof by google.
the class DsaTest method testKeyGeneration.
@SuppressWarnings("InsecureCryptoUsage")
public void testKeyGeneration(int keysize) throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
generator.initialize(keysize);
KeyPair keyPair = generator.generateKeyPair();
DSAPrivateKey priv = (DSAPrivateKey) keyPair.getPrivate();
DSAParams params = priv.getParams();
assertEquals(keysize, params.getP().bitLength());
// The NIST standard does not fully specify the size of q that
// must be used for a given key size. Hence there are differences.
// For example if keysize = 2048, then OpenSSL uses 256 bit q's by default,
// but the SUN provider uses 224 bits. Both are acceptable sizes.
// The tests below simply asserts that the size of q does not decrease the
// overall security of the DSA.
int qsize = params.getQ().bitLength();
switch(keysize) {
case 1024:
assertTrue("Invalid qsize for 1024 bit key:" + qsize, qsize >= 160);
break;
case 2048:
assertTrue("Invalid qsize for 2048 bit key:" + qsize, qsize >= 224);
break;
case 3072:
assertTrue("Invalid qsize for 3072 bit key:" + qsize, qsize >= 256);
break;
default:
fail("Invalid key size:" + keysize);
}
// Check the length of the private key.
// For example GPG4Browsers or the KJUR library derived from it use
// q.bitCount() instead of q.bitLength() to determine the size of the private key
// and hence would generate keys that are much too small.
assertTrue(priv.getX().bitLength() >= qsize - 32);
}
use of java.security.interfaces.DSAPrivateKey in project wycheproof by google.
the class DsaTest method testTiming.
/**
* This test checks for potential of a timing attack. The test generates a number of signatures,
* selects a fraction of them with a small timing and then compares the values k for the selected
* signatures with a normal distribution. The test fails if these ks are much smaller than
* expected. An implementation flaw that can lead to a test failure is to compute the signature
* with a modular exponentiation with a runtime that depend on the length of the exponent.
*
* <p>A failing test simply means that the timing can be used to get information about k. Further
* analysis is necessary to determine if the bias is exploitable and how many timings are
* necessary for an attack. A passing test does not mean that the implementation is secure against
* timing attacks. The test only catches relatively big timing differences. It requires high
* confidence to fail. Noise on the test machine can prevent that a relation between timing and k
* can be detected.
*
* <p>Claims of what is exploitable: http://www.hpl.hp.com/techreports/1999/HPL-1999-90.pdf 30
* signatures are sufficient to find the private key if the attacker knows 8 bits of each k.
* http://eprint.iacr.org/2004/277.pdf 27 signatures are sufficient if 8 bits of each k is known.
* Our own old experiments (using 1GB memory on a Pentium-4? CPU): 2^11 signatures are sufficient
* with a 3 bit leakage. 2^15 signatures are sufficient with a 2 bit leakage. 2^24 signatures are
* sufficient with a 1 bit leakage. Estimate for biased generation in the NIST standard: e.g. 2^22
* signatures, 2^40 memory, 2^64 time
*
* <p><b>Sample output for the SUN provider:</b> <code>
* count:50000 cutoff:4629300 relative average:0.9992225872624547 sigmas:0.3010906585642381
* count:25000 cutoff:733961 relative average:0.976146066585879 sigmas:6.532668708070148
* count:12500 cutoff:688305 relative average:0.9070352192339134 sigmas:18.00255238454385
* count:6251 cutoff:673971 relative average:0.7747148791368986 sigmas:30.850903417893825
* count:3125 cutoff:667045 relative average:0.5901994097874541 sigmas:39.67877152897901
* count:1563 cutoff:662088 relative average:0.4060286694971057 sigmas:40.67294313795137
* count:782 cutoff:657921 relative average:0.2577955312387898 sigmas:35.94906247333319
* count:391 cutoff:653608 relative average:0.1453438859272699 sigmas:29.271192100879457
* count:196 cutoff:649280 relative average:0.08035497211567771 sigmas:22.300206785132406
* count:98 cutoff:645122 relative average:0.05063589092661368 sigmas:16.27820353139225
* count:49 cutoff:641582 relative average:0.018255560447883384 sigmas:11.903018745467488
* count:25 cutoff:638235 relative average:0.009082660721102722 sigmas:8.581595888660086
* count:13 cutoff:633975 relative average:0.0067892346039088326 sigmas:6.20259924188633
* </code>
*
* <p><b>What this shows:</b> The first line uses all 50'000 signatures. The average k of these
* signatures is close to the expected value q/2. Being more selective gives us signatures with a
* more biased k. For example, the 196 signatures with the fastest timing have about a 3-bit bias.
* From this we expect that 2^19 signatures and timings are sufficient to find the private key.
*
* <p>A list of problems caught by this test:
*
* <ul>
* <li>CVE-2016-5548 OpenJDK8's DSA is vulnerable to timing attacks.
* <li>CVE-2016-1000341 BouncyCastle before v 1.56 is vulnernerable to timing attacks.
* </ul>
*/
@SlowTest(providers = { ProviderType.BOUNCY_CASTLE, ProviderType.OPENJDK, ProviderType.SPONGY_CASTLE })
@SuppressWarnings("InsecureCryptoUsage")
@Test
public void testTiming() throws Exception {
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
if (!bean.isCurrentThreadCpuTimeSupported()) {
System.out.println("getCurrentThreadCpuTime is not supported. Skipping");
return;
}
String hashAlgorithm = "SHA-1";
String message = "Hello";
byte[] messageBytes = message.getBytes("UTF-8");
byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(messageBytes);
BigInteger h = new BigInteger(1, digest);
KeyPairGenerator generator = java.security.KeyPairGenerator.getInstance("DSA");
generator.initialize(1024);
KeyPair keyPair = generator.generateKeyPair();
DSAPrivateKey priv = (DSAPrivateKey) keyPair.getPrivate();
Signature signer = Signature.getInstance("SHA1WITHDSA");
signer.initSign(priv);
// The timings below are quite noisy. Thus we need a large number of samples.
int samples = 50000;
long[] timing = new long[samples];
BigInteger[] k = new BigInteger[samples];
for (int i = 0; i < samples; i++) {
long start = bean.getCurrentThreadCpuTime();
signer.update(messageBytes);
byte[] signature = signer.sign();
timing[i] = bean.getCurrentThreadCpuTime() - start;
k[i] = extractK(signature, h, priv, false);
}
long[] sorted = Arrays.copyOf(timing, timing.length);
Arrays.sort(sorted);
// Here we are only interested in roughly the 8 most significant bits of the ks.
// Hence, using double is sufficiently precise.
double q = priv.getParams().getQ().doubleValue();
double expectedAverage = q / 2;
double maxSigmas = 0;
System.out.println("testTiming: SHA1WITHDSA");
for (int idx = samples - 1; idx > 10; idx /= 2) {
long cutoff = sorted[idx];
int count = 0;
double total = 0;
for (int i = 0; i < samples; i++) {
if (timing[i] <= cutoff) {
total += k[i].doubleValue();
count += 1;
}
}
double expectedStdDev = q / Math.sqrt(12 * count);
double average = total / count;
// Number of standard deviations that the average is away from
// the expected value:
double sigmas = Math.abs(expectedAverage - average) / expectedStdDev;
if (sigmas > maxSigmas) {
maxSigmas = sigmas;
}
System.out.println("count:" + count + " cutoff:" + cutoff + " relative average:" + (average / expectedAverage) + " sigmas:" + sigmas);
}
// than 10^{-10}.
if (maxSigmas >= 7) {
fail("Signatures with short timing have a biased k");
}
}
use of java.security.interfaces.DSAPrivateKey in project wycheproof by google.
the class DsaTest method testBiasSha1WithDSA.
/**
* Checks whether CVE-2016-0695 has been fixed. Before the April 2016 security update, the SUN
* provider had a serious flaw that leaked the private key with about 3-5 signatures. In
* particular, "Sha1WithDSA" always generated 160 bit k's independently of q. Unfortunately, it is
* easily possible to use 2048 and 3072 bit DSA keys together with SHA1WithDSA. All a user has to
* do is to use the algorithm name "DSA" instead of "SHA256WithDSA" rsp. "SHA224WithDSA".
*
* <p>An algorithm to extract the key from the signatures has been described for example in the
* paper <a href="http://www.hpl.hp.com/techreports/1999/HPL-1999-90.pdf">Lattice Attacks on
* Digital Signature Schemes</a> by N.A. Howgrave-Graham, N.P. Smart.
*
* <p>This bug is the same as US-CERT: VU # 940388: GnuPG generated ElGamal signatures that leaked
* the private key.
*/
@SlowTest(providers = { ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE })
@SuppressWarnings("InsecureCryptoUsage")
@Test
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;
}
}
Aggregations