Skip to content

Commit 1127131

Browse files
committed
Added TLS validation check for DH keys
Added further agreement result checks
1 parent 63c5f15 commit 1127131

File tree

5 files changed

+55
-10
lines changed

5 files changed

+55
-10
lines changed

Diff for: core/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
77
import org.bouncycastle.crypto.CipherParameters;
88
import org.bouncycastle.crypto.generators.DHKeyPairGenerator;
9+
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
910
import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
1011
import org.bouncycastle.crypto.params.DHParameters;
11-
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
1212
import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
13-
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
13+
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
1414
import org.bouncycastle.crypto.params.ParametersWithRandom;
1515

1616
/**
@@ -26,6 +26,8 @@
2626
*/
2727
public class DHAgreement
2828
{
29+
private static final BigInteger ONE = BigInteger.valueOf(1);
30+
2931
private DHPrivateKeyParameters key;
3032
private DHParameters dhParams;
3133
private BigInteger privateValue;
@@ -89,6 +91,12 @@ public BigInteger calculateAgreement(
8991

9092
BigInteger p = dhParams.getP();
9193

92-
return message.modPow(key.getX(), p).multiply(pub.getY().modPow(privateValue, p)).mod(p);
94+
BigInteger result = pub.getY().modPow(privateValue, p);
95+
if (result.compareTo(ONE) == 0)
96+
{
97+
throw new IllegalStateException("Shared key can't be 1");
98+
}
99+
100+
return message.modPow(key.getX(), p).multiply(result).mod(p);
93101
}
94102
}

Diff for: core/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
public class DHBasicAgreement
2121
implements BasicAgreement
2222
{
23+
private static final BigInteger ONE = BigInteger.valueOf(1);
24+
2325
private DHPrivateKeyParameters key;
2426
private DHParameters dhParams;
2527

@@ -66,6 +68,12 @@ public BigInteger calculateAgreement(
6668
throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
6769
}
6870

69-
return pub.getY().modPow(key.getX(), dhParams.getP());
71+
BigInteger result = pub.getY().modPow(key.getX(), dhParams.getP());
72+
if (result.compareTo(ONE) == 0)
73+
{
74+
throw new IllegalStateException("Shared key can't be 1");
75+
}
76+
77+
return result;
7078
}
7179
}

Diff for: core/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java

+4
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,10 @@ public byte[] processBlock(
408408
{
409409
throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
410410
}
411+
catch (IllegalArgumentException e)
412+
{
413+
throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
414+
}
411415

412416
int encLength = (inLen - bIn.available());
413417
this.V = Arrays.copyOfRange(in, inOff, inOff + encLength);

Diff for: core/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
public class DHPublicKeyParameters
66
extends DHKeyParameters
77
{
8+
private static final BigInteger ONE = BigInteger.valueOf(1);
9+
private static final BigInteger TWO = BigInteger.valueOf(2);
10+
811
private BigInteger y;
912

1013
public DHPublicKeyParameters(
@@ -18,9 +21,14 @@ public DHPublicKeyParameters(
1821

1922
private BigInteger validate(BigInteger y, DHParameters dhParams)
2023
{
24+
if (y == null)
25+
{
26+
throw new NullPointerException("y value cannot be null");
27+
}
28+
2129
if (dhParams.getQ() != null)
2230
{
23-
if (BigInteger.ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP())))
31+
if (ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP())))
2432
{
2533
return y;
2634
}
@@ -29,6 +37,12 @@ private BigInteger validate(BigInteger y, DHParameters dhParams)
2937
}
3038
else
3139
{
40+
// TLS check
41+
if (y.compareTo(TWO) < 0 || y.compareTo(dhParams.getP().subtract(TWO)) > 0)
42+
{
43+
throw new IllegalArgumentException("invalid DH public key");
44+
}
45+
3246
return y; // we can't validate without Q.
3347
}
3448
}

Diff for: prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java

+16-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
public class KeyAgreementSpi
3030
extends BaseAgreementSpi
3131
{
32+
private static final BigInteger ONE = BigInteger.valueOf(1);
33+
private static final BigInteger TWO = BigInteger.valueOf(2);
34+
3235
private BigInteger x;
3336
private BigInteger p;
3437
private BigInteger g;
@@ -101,14 +104,22 @@ protected Key engineDoPhase(
101104
throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
102105
}
103106

104-
if (lastPhase)
107+
BigInteger peerY = ((DHPublicKey)key).getY();
108+
if (peerY == null || peerY.compareTo(TWO) < 0
109+
|| peerY.compareTo(p.subtract(ONE)) >= 0)
105110
{
106-
result = ((DHPublicKey)key).getY().modPow(x, p);
107-
return null;
111+
throw new InvalidKeyException("Invalid DH PublicKey");
108112
}
109-
else
113+
114+
result = peerY.modPow(x, p);
115+
if (result.compareTo(ONE) == 0)
110116
{
111-
result = ((DHPublicKey)key).getY().modPow(x, p);
117+
throw new InvalidKeyException("Shared key can't be 1");
118+
}
119+
120+
if (lastPhase)
121+
{
122+
return null;
112123
}
113124

114125
return new BCDHPublicKey(result, pubKey.getParams());

0 commit comments

Comments
 (0)