blob: ccb4542c5019aface6366dd82f9017d71b7ea7f7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
package org.bouncycastle.crypto.tls;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.agreement.DHBasicAgreement;
import org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator;
import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
import org.bouncycastle.util.BigIntegers;
public class TlsDHUtils {
static final BigInteger ONE = BigInteger.valueOf(1);
static final BigInteger TWO = BigInteger.valueOf(2);
public static byte[] calculateDHBasicAgreement(DHPublicKeyParameters publicKey,
DHPrivateKeyParameters privateKey) {
DHBasicAgreement basicAgreement = new DHBasicAgreement();
basicAgreement.init(privateKey);
BigInteger agreementValue = basicAgreement.calculateAgreement(publicKey);
/*
* RFC 5246 8.1.2. Leading bytes of Z that contain all zero bits are stripped before it is
* used as the pre_master_secret.
*/
return BigIntegers.asUnsignedByteArray(agreementValue);
}
public static AsymmetricCipherKeyPair generateDHKeyPair(SecureRandom random,
DHParameters dhParams) {
DHBasicKeyPairGenerator dhGen = new DHBasicKeyPairGenerator();
dhGen.init(new DHKeyGenerationParameters(random, dhParams));
return dhGen.generateKeyPair();
}
public static DHPrivateKeyParameters generateEphemeralClientKeyExchange(SecureRandom random,
DHParameters dhParams, OutputStream output) throws IOException {
AsymmetricCipherKeyPair dhAgreeClientKeyPair = generateDHKeyPair(random, dhParams);
DHPrivateKeyParameters dhAgreeClientPrivateKey = (DHPrivateKeyParameters) dhAgreeClientKeyPair
.getPrivate();
BigInteger Yc = ((DHPublicKeyParameters) dhAgreeClientKeyPair.getPublic()).getY();
byte[] keData = BigIntegers.asUnsignedByteArray(Yc);
TlsUtils.writeOpaque16(keData, output);
return dhAgreeClientPrivateKey;
}
public static DHPublicKeyParameters validateDHPublicKey(DHPublicKeyParameters key)
throws IOException {
BigInteger Y = key.getY();
DHParameters params = key.getParameters();
BigInteger p = params.getP();
BigInteger g = params.getG();
if (!p.isProbablePrime(2)) {
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
if (g.compareTo(TWO) < 0 || g.compareTo(p.subtract(TWO)) > 0) {
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
if (Y.compareTo(TWO) < 0 || Y.compareTo(p.subtract(ONE)) > 0) {
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
// TODO See RFC 2631 for more discussion of Diffie-Hellman validation
return key;
}
public static BigInteger readDHParameter(InputStream input) throws IOException {
return new BigInteger(1, TlsUtils.readOpaque16(input));
}
public static void writeDHParameter(BigInteger x, OutputStream output) throws IOException {
TlsUtils.writeOpaque16(BigIntegers.asUnsignedByteArray(x), output);
}
}
|