diff options
Diffstat (limited to 'core/src/main/java/org/spongycastle/crypto/tls/TlsDHUtils.java')
-rw-r--r-- | core/src/main/java/org/spongycastle/crypto/tls/TlsDHUtils.java | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/crypto/tls/TlsDHUtils.java b/core/src/main/java/org/spongycastle/crypto/tls/TlsDHUtils.java new file mode 100644 index 00000000..9a7a2218 --- /dev/null +++ b/core/src/main/java/org/spongycastle/crypto/tls/TlsDHUtils.java @@ -0,0 +1,105 @@ +package org.spongycastle.crypto.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.agreement.DHBasicAgreement; +import org.spongycastle.crypto.generators.DHBasicKeyPairGenerator; +import org.spongycastle.crypto.params.DHKeyGenerationParameters; +import org.spongycastle.crypto.params.DHParameters; +import org.spongycastle.crypto.params.DHPrivateKeyParameters; +import org.spongycastle.crypto.params.DHPublicKeyParameters; +import org.spongycastle.util.BigIntegers; + +public class TlsDHUtils +{ + static final BigInteger ONE = BigInteger.valueOf(1); + static final BigInteger TWO = BigInteger.valueOf(2); + + public static boolean areCompatibleParameters(DHParameters a, DHParameters b) + { + return a.getP().equals(b.getP()) && a.getG().equals(b.getG()); + } + + 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 kp = generateDHKeyPair(random, dhParams); + + DHPublicKeyParameters dh_public = (DHPublicKeyParameters) kp.getPublic(); + writeDHParameter(dh_public.getY(), output); + + return (DHPrivateKeyParameters) kp.getPrivate(); + } + + public static DHPrivateKeyParameters generateEphemeralServerKeyExchange(SecureRandom random, DHParameters dhParams, + OutputStream output) throws IOException + { + AsymmetricCipherKeyPair kp = TlsDHUtils.generateDHKeyPair(random, dhParams); + + DHPublicKeyParameters dhPublicKey = (DHPublicKeyParameters)kp.getPublic(); + ServerDHParams params = new ServerDHParams(dhPublicKey); + params.encode(output); + + return (DHPrivateKeyParameters)kp.getPrivate(); + } + + 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); + } +} |