--- a/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java Tue Mar 20 12:48:48 2012 +0100
+++ b/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java Tue Mar 20 15:06:13 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.ProviderException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.KeyAgreementSpi;
@@ -234,31 +235,14 @@
protected byte[] engineGenerateSecret()
throws IllegalStateException
{
- if (generateSecret == false) {
- throw new IllegalStateException
- ("Key agreement has not been completed yet");
+ int expectedLen = (init_p.bitLength() + 7) >>> 3;
+ byte[] result = new byte[expectedLen];
+ try {
+ engineGenerateSecret(result, 0);
+ } catch (ShortBufferException sbe) {
+ // should never happen since length are identical
}
-
- // Reset the key agreement here (in case anything goes wrong)
- generateSecret = false;
-
- // get the modulus
- BigInteger modulus = init_p;
-
- BigInteger tmpResult = y.modPow(x, modulus);
- byte[] secret = tmpResult.toByteArray();
-
- /*
- * BigInteger.toByteArray will sometimes put a sign byte up front, but
- * we NEVER want one.
- */
- if ((tmpResult.bitLength() % 8) == 0) {
- byte retval[] = new byte[secret.length - 1];
- System.arraycopy(secret, 1, retval, 0, retval.length);
- return retval;
- } else {
- return secret;
- }
+ return result;
}
/**
@@ -301,39 +285,51 @@
}
BigInteger modulus = init_p;
- byte[] secret = this.y.modPow(this.x, modulus).toByteArray();
-
- // BigInteger.toByteArray will sometimes put a sign byte up front,
- // but we NEVER want one.
- if ((secret.length << 3) != modulus.bitLength()) {
- if ((sharedSecret.length - offset) < (secret.length - 1)) {
- throw new ShortBufferException
+ int expectedLen = (modulus.bitLength() + 7) >>> 3;
+ if ((sharedSecret.length - offset) < expectedLen) {
+ throw new ShortBufferException
("Buffer too short for shared secret");
- }
- System.arraycopy(secret, 1, sharedSecret, offset,
- secret.length - 1);
+ }
- // Reset the key agreement here (not earlier!), so that people
- // can recover from ShortBufferException above without losing
- // internal state
- generateSecret = false;
+ // Reset the key agreement after checking for ShortBufferException
+ // above, so user can recover w/o losing internal state
+ generateSecret = false;
- return secret.length - 1;
-
+ /*
+ * NOTE: BigInteger.toByteArray() returns a byte array containing
+ * the two's-complement representation of this BigInteger with
+ * the most significant byte is in the zeroth element. This
+ * contains the minimum number of bytes required to represent
+ * this BigInteger, including at least one sign bit whose value
+ * is always 0.
+ *
+ * Keys are always positive, and the above sign bit isn't
+ * actually used when representing keys. (i.e. key = new
+ * BigInteger(1, byteArray)) To obtain an array containing
+ * exactly expectedLen bytes of magnitude, we strip any extra
+ * leading 0's, or pad with 0's in case of a "short" secret.
+ */
+ byte[] secret = this.y.modPow(this.x, modulus).toByteArray();
+ if (secret.length == expectedLen) {
+ System.arraycopy(secret, 0, sharedSecret, offset,
+ secret.length);
} else {
- if ((sharedSecret.length - offset) < secret.length) {
- throw new ShortBufferException
- ("Buffer too short to hold shared secret");
+ // Array too short, pad it w/ leading 0s
+ if (secret.length < expectedLen) {
+ System.arraycopy(secret, 0, sharedSecret,
+ offset + (expectedLen - secret.length),
+ secret.length);
+ } else {
+ // Array too long, check and trim off the excess
+ if ((secret.length == (expectedLen+1)) && secret[0] == 0) {
+ // ignore the leading sign byte
+ System.arraycopy(secret, 1, sharedSecret, offset, expectedLen);
+ } else {
+ throw new ProviderException("Generated secret is out-of-range");
+ }
}
- System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
-
- // Reset the key agreement here (not earlier!), so that people
- // can recover from ShortBufferException above without losing
- // internal state
- generateSecret = false;
-
- return secret.length;
}
+ return expectedLen;
}
/**