001: /*
002: * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.security.ssl;
027:
028: import java.math.BigInteger;
029: import java.security.*;
030:
031: import javax.crypto.SecretKey;
032: import javax.crypto.KeyAgreement;
033: import javax.crypto.interfaces.DHPublicKey;
034: import javax.crypto.spec.*;
035:
036: /**
037: * This class implements the Diffie-Hellman key exchange algorithm.
038: * D-H means combining your private key with your partners public key to
039: * generate a number. The peer does the same with its private key and our
040: * public key. Through the magic of Diffie-Hellman we both come up with the
041: * same number. This number is secret (discounting MITM attacks) and hence
042: * called the shared secret. It has the same length as the modulus, e.g. 512
043: * or 1024 bit. Man-in-the-middle attacks are typically countered by an
044: * independent authentication step using certificates (RSA, DSA, etc.).
045: *
046: * The thing to note is that the shared secret is constant for two partners
047: * with constant private keys. This is often not what we want, which is why
048: * it is generally a good idea to create a new private key for each session.
049: * Generating a private key involves one modular exponentiation assuming
050: * suitable D-H parameters are available.
051: *
052: * General usage of this class (TLS DHE case):
053: * . if we are server, call DHCrypt(keyLength,random). This generates
054: * an ephemeral keypair of the request length.
055: * . if we are client, call DHCrypt(modulus, base, random). This
056: * generates an ephemeral keypair using the parameters specified by the server.
057: * . send parameters and public value to remote peer
058: * . receive peers ephemeral public key
059: * . call getAgreedSecret() to calculate the shared secret
060: *
061: * In TLS the server chooses the parameter values itself, the client must use
062: * those sent to it by the server.
063: *
064: * The use of ephemeral keys as described above also achieves what is called
065: * "forward secrecy". This means that even if the authentication keys are
066: * broken at a later date, the shared secret remains secure. The session is
067: * compromised only if the authentication keys are already broken at the
068: * time the key exchange takes place and an active MITM attack is used.
069: * This is in contrast to straightforward encrypting RSA key exchanges.
070: *
071: * @version 1.33 05/05/07
072: * @author David Brownell
073: */
074: final class DHCrypt {
075:
076: // group parameters (prime modulus and generator)
077: private BigInteger modulus; // P (aka N)
078: private BigInteger base; // G (aka alpha)
079:
080: // our private key (including private component x)
081: private PrivateKey privateKey;
082:
083: // public component of our key, X = (g ^ x) mod p
084: private BigInteger publicValue; // X (aka y)
085:
086: /**
087: * Generate a Diffie-Hellman keypair of the specified size.
088: */
089: DHCrypt(int keyLength, SecureRandom random) {
090: try {
091: KeyPairGenerator kpg = JsseJce
092: .getKeyPairGenerator("DiffieHellman");
093: kpg.initialize(keyLength, random);
094: KeyPair kp = kpg.generateKeyPair();
095: privateKey = kp.getPrivate();
096: DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
097: publicValue = spec.getY();
098: modulus = spec.getP();
099: base = spec.getG();
100: } catch (GeneralSecurityException e) {
101: throw new RuntimeException("Could not generate DH keypair",
102: e);
103: }
104: }
105:
106: /**
107: * Generate a Diffie-Hellman keypair using the specified parameters.
108: *
109: * @param modulus the Diffie-Hellman modulus P
110: * @param base the Diffie-Hellman base G
111: */
112: DHCrypt(BigInteger modulus, BigInteger base, SecureRandom random) {
113: this .modulus = modulus;
114: this .base = base;
115: try {
116: KeyPairGenerator kpg = JsseJce
117: .getKeyPairGenerator("DiffieHellman");
118: DHParameterSpec params = new DHParameterSpec(modulus, base);
119: kpg.initialize(params, random);
120: KeyPair kp = kpg.generateKeyPair();
121: privateKey = kp.getPrivate();
122: DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
123: publicValue = spec.getY();
124: } catch (GeneralSecurityException e) {
125: throw new RuntimeException("Could not generate DH keypair",
126: e);
127: }
128: }
129:
130: static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) {
131: if (key instanceof DHPublicKey) {
132: DHPublicKey dhKey = (DHPublicKey) key;
133: DHParameterSpec params = dhKey.getParams();
134: return new DHPublicKeySpec(dhKey.getY(), params.getP(),
135: params.getG());
136: }
137: try {
138: KeyFactory factory = JsseJce.getKeyFactory("DH");
139: return (DHPublicKeySpec) factory.getKeySpec(key,
140: DHPublicKeySpec.class);
141: } catch (Exception e) {
142: throw new RuntimeException(e);
143: }
144: }
145:
146: /** Returns the Diffie-Hellman modulus. */
147: BigInteger getModulus() {
148: return modulus;
149: }
150:
151: /** Returns the Diffie-Hellman base (generator). */
152: BigInteger getBase() {
153: return base;
154: }
155:
156: /**
157: * Gets the public key of this end of the key exchange.
158: */
159: BigInteger getPublicKey() {
160: return publicValue;
161: }
162:
163: /**
164: * Get the secret data that has been agreed on through Diffie-Hellman
165: * key agreement protocol. Note that in the two party protocol, if
166: * the peer keys are already known, no other data needs to be sent in
167: * order to agree on a secret. That is, a secured message may be
168: * sent without any mandatory round-trip overheads.
169: *
170: * <P>It is illegal to call this member function if the private key
171: * has not been set (or generated).
172: *
173: * @param peerPublicKey the peer's public key.
174: * @returns the secret, which is an unsigned big-endian integer
175: * the same size as the Diffie-Hellman modulus.
176: */
177: SecretKey getAgreedSecret(BigInteger peerPublicValue) {
178: try {
179: KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman");
180: DHPublicKeySpec spec = new DHPublicKeySpec(peerPublicValue,
181: modulus, base);
182: PublicKey publicKey = kf.generatePublic(spec);
183: KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
184: ka.init(privateKey);
185: ka.doPhase(publicKey, true);
186: return ka.generateSecret("TlsPremasterSecret");
187: } catch (GeneralSecurityException e) {
188: throw new RuntimeException("Could not generate secret", e);
189: }
190: }
191:
192: }
|