The Diffie-Hellman Key Exchange

  

The Diffie-Hellman (DH) key exchange was the first key exchange and the first to mention a public key. The key was first documented in 1979. The purpose of DH is key exchange; it does not define cipher suites.

Whitfield Diffie and Martin Hellman, from Stanford University, first published the public key algorithm in 1976. The DH algorithm enables two parties to compute a shared secret. The algorithm doesn't require encryption for low overhead. The fundamental concept underlying the DH algorithm is the mathematical difficulty of calculating discrete logarithms in a finite field.

Understanding the Diffie-Hellman key exchange

The key agreement for DH follows this procedure for User A and User B:

  • First, an agreement between User A and User B is made on two large prime numbers , p and g.

  • Next , User A generates a random number, Xa, and User B generates a random number, Xb; each must be less than p - 2.

  • User A then calculates Ya and sends the results to User B.

    Ya = g Xa mod p

  • User B then calculates Yb and sends the results to User A.

    Yb = g Xb mod p

  • User A computes K = Ya Xa mod p = g XaXb mod p .

  • User B computes K = Yb Xb mod p = g XaXb mod p .

The only calculations that are actually seen across the network are Ya and Yb. From Ya and Yb alone, the key cannot be determined. The user needs the p and g to perform the calculations. The p and g are normally agreed upon through a secure means, but without the user ever seeing Xa or Xb, the key cannot be derived. Listing 4-6 gives a small demonstration of these calculations.

Listing 4-6: Diffie-Hellman example
start example
 An example: Step 1: p = 47 g = 71     Step 2: Xa = 9 Xb = 14     Step 3: Ya = (71) ^ 9 mod 47 = 28 71  9  mod 47 = 45848500718449031 mod 47 = 28 45848500718449031 / 47 roughly equals 975500015286149 975500015286149 * 47 = 45848500718449003 45848500718449031 - 45848500718449003 = 28 Send Ya.     Step 4: Yb = (71) ^ 14 mod 47 = 42 71  14  mod 47 = 82721210695570328927708881 mod 47 = 42 82721210695570328927708881 / 47 roughly equals 1760025759480219764419337 1760025759480219764419337 * 47 = 82721210695570328927708839 82721210695570328927708881 - 82721210695570328927708839 = 42 Send Yb.     Step 5: K = Ya  Xa  mod p 28  9  mod 47 = 10578455953408 mod 47 = 27 10578455953408 / 47 roughly equals 225073530923 225073530923 * 47 = 10578455953381 10578455953408 - 10578455953381 = 27 Users A, Key = 27     Step 5: K = Yb  Xb  mod p 42  14  mod 47 = 53148384174432398229504 mod 47 = 27 53148384174432398229504 / 47 roughly equals 1130816684562391451691 1130816684562391451691 * 47 = 53148384174432398229477 53148384174432398229504 - 53148384174432398229477 = 27 Users B, Key = 27 
end example
 

Listing 4-6 shows that User A and User B derived the same secret key with only disclosing to each other a piece of their information.

Implementing the Diffie-Hellman key exchange

Listing 4-7 demonstrates the same calculation in Java. The example also demonstrates two more DH key generations with larger primes, one where the algorithm will choose p and g , and another where p and g are chosen and passed into the algorithm. See if the output in Listing 4-8 gives the same number for the first part, and observe the keys that DH will normally generate.

Listing 4-7: The DHSimpleApp class: A sample application generating keys
start example
 package com.richware.chap04;  import java.util.*; import java.math.*; import java.security.*; import javax.crypto.spec.*;     /**  * Class DHSimpleApp  * Description: This is an example of a  * simple Diffie-Hellman  *  * Copyright:    Copyright (c) 2002 Wiley Publishing, Inc.  * @author Rich Helton <rhelton@richware.com>  * @version 1.0    * DISCLAIMER: Please refer to the disclaimer at the beginning of this book.  */ public class DHSimpleApp  {   public final static int pValue  = 47;   public final static int gValue  = 71;   public final static int XaValue = 9;   public final static int XbValue = 14;   /**    * Method main    * Description: Main Driver    * @param args none    *    */   public static void main(String[] args)    {     try      {       System.out.println();       System.out.println(         "DH Proving the algorithm*************************");           /*        * Step 1        * Pick p and q        */       BigInteger p = new BigInteger(Integer.toString(pValue));       BigInteger g = new BigInteger(Integer.toString(gValue));       System.out.println("p = " + p);       System.out.println("g = " + g);           /*        * Step 2        * Select the random numbers        */       BigInteger Xa =         new BigInteger(Integer.toString(XaValue));       BigInteger Xb =         new BigInteger(Integer.toString(XbValue));       System.out.println("Xa = " + Xa);       System.out.println("Xb = " + Xb);           /*        * Step 3        * Calculate Ya        */       BigInteger Ya = g.modPow(Xa, p);        System.out.println("Ya = " + Ya);           /*        * Step 4        * Calculate Yb        */       BigInteger Yb = g.modPow(Xb, p);       System.out.println("Yb = " + Yb);           /*        * Step 5        * User A calculates K        */       BigInteger Ka = Ya.modPow(Xa, p);       System.out.println("Users A, K = " + Ka);           /*        * Step 6        * User B calculates K        */       BigInteger Kb = Yb.modPow(Xb, p);       System.out.println("Users B, K = " + Kb);       DHSimpleApp app = new DHSimpleApp();       app.createKey();           /*        * Generate a 512 bit Prime to pass as p and g        */       int          bitLength = 512;  // 512 bits       SecureRandom rnd       = new SecureRandom();       System.out.println("BitLength : " + bitLength);       System.out         .println("Selecting Prime Numbers..............");       p = BigInteger.probablePrime(bitLength, rnd);       g = BigInteger.probablePrime(bitLength, rnd);       System.out.println("P *********************");       System.out.println(p);        System.out.println("G *********************");       System.out.println(g);       app.createSpecificKey(p, g);     }         /*      * Catches      */     catch (Exception ex)      {       ex.printStackTrace();     }   }       /**    * Method createKey    * Description: This is an example of    * letting the algorithm choose    * the values    *    */   public void createKey()    {     try      {       System.out.println();       System.out.println(         "Diffie-Hellman letting the algorithm choose******************");       KeyPairGenerator kpg =         KeyPairGenerator.getInstance("DiffieHellman");       /*        * A strong key uses 512 to 2048 bits        * the bits must be multiples of 64        */       System.out.println("Provider =" + kpg.getProvider());       kpg.initialize(512);       KeyPair kp = kpg.generateKeyPair();       /*        * Read the keys        * produced by the algorithm        */       System.out.println("Public Key ="                          + kp.getPublic().getEncoded());       System.out.println("Public Key Algorithm ="                          + kp.getPublic().getAlgorithm());       System.out.println("Public Key Format ="                          + kp.getPublic().getFormat());       System.out.println("Private Key ="                          + kp.getPrivate().getEncoded());       System.out.println("Private Key Algorithm ="                          + kp.getPrivate().getAlgorithm());       System.out.println("Private Key Format ="                          + kp.getPrivate().getFormat());       /*        * Initialize the KeyFactory for DSA        */       KeyFactory kfactory =         KeyFactory.getInstance("DiffieHellman");       /*        * Create the DH public key spec        */       DHPublicKeySpec kspec =         (DHPublicKeySpec) kfactory           .getKeySpec(kp.getPublic(), DHPublicKeySpec.class);       /*        * Print out public key values        */       System.out         .println("Public Key Y **********************");       System.out.println(kspec.getY());       System.out         .println("Public Key G **********************");       System.out.println(kspec.getG());       System.out         .println("Public Key P **********************");       System.out.println(kspec.getP());     }     /*      * Catches      */     catch (java.security.NoSuchAlgorithmException ex)      {       ex.printStackTrace();     }     catch (Exception ex)      {       ex.printStackTrace();     }   }       /**    * Method createSpecificKey    * Description: This is an example of    * choosing e    *    */   public void createSpecificKey(BigInteger p, BigInteger g)    {     try      {       /*        * Another provider specific to the signature instead of JSSE        */       System.out.println();       System.out.println(         "Diffie-Hellman Choosing the prime, must be at least 512 bits***********************");       KeyPairGenerator kpg =         KeyPairGenerator.getInstance("DiffieHellman");       /* A strong key uses 512 to 2048 bits        * the bits must be multiples of 64        */       System.out.println("Provider =" + kpg.getProvider());       /*        * Select the parameters        */           /*        * Step 1        * Pick p and q        */       DHParameterSpec param = new DHParameterSpec(p, g);       kpg.initialize(param);       KeyPair kp = kpg.generateKeyPair();       /* Read the keys        * produced by the algorithm        */       System.out.println("Public Key ="                          + kp.getPublic().getEncoded());       System.out.println("Public Key Algorithm ="                          + kp.getPublic().getAlgorithm());       System.out.println("Public Key Format ="                          + kp.getPublic().getFormat());       System.out.println("Private Key ="                          + kp.getPrivate().getEncoded());       System.out.println("Private Key Algorithm ="                          + kp.getPrivate().getAlgorithm());       System.out.println("Private Key Format ="                          + kp.getPrivate().getFormat());       /*        * Initialize the KeyFactory for DSA        */       KeyFactory kfactory =         KeyFactory.getInstance("DiffieHellman");       /*        * Create the DH public key spec        */       DHPublicKeySpec kspec =         (DHPublicKeySpec) kfactory           .getKeySpec(kp.getPublic(), DHPublicKeySpec.class);       /*        * Print out public key values        */       System.out         .println("Public Key Y **********************");       System.out.println(kspec.getY());       System.out         .println("Public Key G **********************");       System.out.println(kspec.getG());       System.out         .println("Public Key P **********************");       System.out.println(kspec.getP());     }     /*      * Catches      */     catch (java.security.NoSuchAlgorithmException ex)      {       ex.printStackTrace();     }     catch (Exception ex)      {       ex.printStackTrace();     }   } } 
end example
 
Note  

This application uses the Java JDK 1.4. For more information go to the SUN JDK1.4 site at http://java.sun.com/j2se/1.4/index.html .

Listing 4-8: Listing 4-7 output
start example
 >java com.richware.chap04.DHSimpleApp DH Proving the algorithm************************* p = 47 g = 71 Xa = 9 Xb = 14 Ya = 28 Yb = 42 Users A, K = 27 Users B, K = 27     Diffie-Hellman letting the algorithm choose****************** Provider =SunJCE version 1.4 Public Key =[B@7f1ba3 Public Key Algorithm =DH Public Key Format =X.509 Private Key =[B@ef8cf3 Private Key Algorithm =DH Private Key Format =PKCS#8 Public Key Y ********************** 215853303947720191394363204632289947856794011423030615847073495337757796 73737061 454452739594295460422026209292888968911791574574840970680271536892303382 37 Public Key G ********************** 780767425941595301110267422100730763013420442221767063544543685333983324 14827022 404673394884252155338179472545533731982875851947335006166139320371210727 79 Public Key P ********************** 115753098675150246496964003698310934933614588075737606163818197287873723 52257166 904645891644283132883296560173559285063331655024682782209092633911135081 389 BitLength : 512 Selecting Prime Numbers.............. P ********************* 130304194260172025300310555476633670352733758838132454143719076151626882 75019700 900991276702721338225276799806050509112690435609866138874960358819030821 331 G ********************* 107337507575903853089503367791494296062280268490832231356557597425184949 82619853 817678166127320431825616129300567049342721065655343674346787417703610508 381     Diffie-Hellman Choosing the prime, must be at least 512 bits******************** *** Provider =SunJCE version 1.4 Public Key =[B@8b819f Public Key Algorithm =DH Public Key Format =X.509 Private Key =[B@eb017e Private Key Algorithm =DH Private Key Format =PKCS#8 Public Key Y ********************** 125278606598212229676245338743389710127962173230624580585131649470352764 57931540 486555545177300397072927115804421228793021332981110882851978543144942240 792 Public Key G ********************** 107337507575903853089503367791494296062280268490832231356557597425184949 82619853 817678166127320431825616129300567049342721065655343674346787417703610508 381 Public Key P ********************** 130304194260172025300310555476633670352733758838132454143719076151626882 75019700 900991276702721338225276799806050509112690435609866138874960358819030821 331 
end example
 

Listing 4-8 came up with the same calculations demonstrated in Listing 4-6. Listing 4-7 shows the code for that calculation, letting the algorithm choose p and g for you, and randomly choosing p and g for populating the DH algorithm. Passing the simple example of p with 47 and g as 71 would not have worked. The p and g that is passed in the algorithm must be 512 bits. Instead of trying to calculate a 512 prime number, it is much easier to let the BigInteger class solve these things. An interesting thing to note is that the DH algorithm is part of an engine class and will have an associated service provider. This is discussed in detail in the next chapter, but there are some interesting points in the code. In the second demonstration in the code, the keys were generated with Listing 4-9.

Listing 4-9: Generating the DH key: An excerpt from Listing 4-7
start example
 KeyPairGenerator kpg =         KeyPairGenerator.getInstance("DiffieHellman");           /*        * A strong key uses 512 to 2048 bits        * the bits must be multiples of 64        */       System.out.println("Provider =" + kpg.getProvider());       kpg.initialize(512); 
end example
 
Cross-Reference  

Chapter 5 discusses the Service Provider Interface in more detail.

Listing 4-9 demonstrates that there is a choice in the key sizes. A key can be created with 512 bits to 2048 bits as long as the intervals in between are multiples of 64 bits. The engine class will call a service provider that will actually implement the algorithm; in this case, it was SunJCE version 1.4 from the output produced. The code in the third calculation DHParameterSpec param = new DHParameterSpec(p, g); will pass the p and g variables into the algorithm. The p and g must be 512 bits because the algorithm is specified to use 512 bits in the kpg.initialize(512); code.

Understanding man-in-the-middle attacks

The DH algorithm was a landmark for calculating keys without passing the key itself, but it does have flaws. The biggest vulnerability that DH faces is the man-in-the-middle attack. The man-in-the-middle attack is possible because there is no authentication that User A or User B is actually User A and User B. A user could be communicating with both User A and User B and impersonating both of them. Call the user in the middle User M. User A could be passing User M his shared values, p , g , and Ya. User M could impersonate User B and return the correct values, while building the shared key for their use. User M could also be doing the same with User B, while impersonating User A. After User M has the correct keys from User A and User B, he could watch the messages from each in the network traffic and continue to impersonate the other user. It might be some time and many messages later that User A and User B discover that they have not actually communicated directly. Figure 4-7 demonstrates this attack.

click to expand
Figure 4-7: The man-in-the-middle attack

The man-in-the-middle attack is an impersonation of both users. The imposter, User M, will pass the correct the responses to each user while generating a secret key that will only work with the corresponding user. Listing 4-10 is an example output of such an attack.

Listing 4-10: An example output of a man-in-the-middle attack
start example
 >java com.richware.chap04.DHAgreement M->Starting User.... A->Starting....     A-> Generating Keys....         A->G Value********************** 686755889625542462913068225455773500476081418006511843594224192648532720 96450315 302477556820215664881075326238197051392423896404898949629998114325553370 73     A->P Value********************** 121342879252870070401982768810332898164534958562066239078599729484086872 39636257 518379548669448217314594891252619981309038447645426521735635034139529123 263     A->Public Key********************** [B@61d36b B->Starting User....         M->A Public Key.... [B@61d36b M->A's P.... 12134287925287007040198276881033289816453495856206623907859972948408687239636257 518379548669448217314594891252619981309038447645426521735635034139529123263     M->A's G.... 68675588962554246291306822545577350047608141800651184359422419264853272096450315 30247755682021566488107532623819705139242389640489894962999811432555337073 M->Generating a Key from A....     M->Sending fake B Public Key to A********************* [B@69ca65     M->New p to B ********************* 12090798597311843726670097664744004279023120419571357926854058941337537240383708 944490845702553153976642382872825280210946033210850498023765243639783740693     M->New g to B ********************* 79927536263708347944576459209391433161144499354657375832786939531843220221538632 64617650061290306019804225892643323961146098814441756462264510605496468689     M->Generated a key to B....     M->Sending fake A Public Key to B********************* [B@a37368 A->Got Public Key from B?....... [B@69ca65         B->User A's Public?********************** [B@a37368 B->User A's G Value?********************** 79927536263708347944576459209391433161144499354657375832786939531843220221538632 64617650061290306019804225892643323961146098814441756462264510605496468689     B->User A's P Value?********************** 12090798597311843726670097664744004279023120419571357926854058941337537240383708 944490845702553153976642382872825280210946033210850498023765243639783740693     B->Public Key********************** [B@8916a2     M->B's Public Key.... [B@8916a2     M->Got Cipher from A->How are you B?     M->Sending different Cipher to B->Are you sure that I am A? B->Got Cipher->Are you sure that I am A? 
end example
 

Listing 4-10 demonstrates User M receiving the correct p and g from User A, and then generating a new p and g to User B. User M will associate his secret key with A, and a new secret key with B. User A and User B will have different secret keys, and User M will have a secret key for each user. User A then might pass a cipher message to User B such as "How are you, B?", which User M might intercept and change to "Are you sure that I am A?" and then send that message instead to User B. If User A actually received a response from User B without User M intervening and changing the keys, then User A would not be able to decrypt the message. User M would have to constantly act as redirector of messages and re-key the messages to both users to avoid getting caught. Listing 4-11 shows sample code for a multi-threaded man-in-the-middle attack. The output is displayed in Listing 4-10.

Listing 4-11: The DHAgreement class: Java code for the man-in-the-middle attack
start example
 package com.richware.chap04;  import java.math.*;  import java.security.*; import java.security.spec.*; import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*;     /**  * Class DHAgreement  * Description: This is an example of a  * man in the middle attack  *  * Copyright:    Copyright (c) 2002 Wiley Publishing, Inc.  * @author Rich Helton <rhelton@richware.com>  * @version 1.0   * DISCLAIMER: Please refer to the disclaimer at the beginning of this book.  */ public class DHAgreement implements Runnable  {   byte                    userA[];  // Public Key from A   byte                    userB[];  // Public Key from B   byte                    userAfromM[];  // Public Key from A altered by M   byte                    userBfromM[];  // Public Key from B altered by M   boolean                 userAStarted = false;   boolean                 userMStarted = false;   byte[]                  ciphertext_from_A;   byte[]                  ciphertext_from_M;  // CipherText from M   public final static int bitLength = 512;  // The size of the key   BigInteger              p, g;        /**    * Method run    */   public synchronized void run()    {     if (!userMStarted)      {       userMStarted = true;       doUserM();     }     else if (!userAStarted)      {       userAStarted = true;       doUserA();     }     else      {       doUserB();     }   }       /**    * Method main    * Description: Main Driver    * @param args none    *    */   public static void main(String[] args)    {     try      {       DHAgreement test = new DHAgreement();       new Thread(test).start();  // Starts User M       new Thread(test).start();  // Starts User A       new Thread(test).start();  // Starts User B     }         /*      * Catches      */     catch (Exception ex)      {       ex.printStackTrace();     }   }       /**    * Method doUserA    */   public synchronized void doUserA()    {     try      {       System.out.println("A->Starting....");       System.out.println();       /*        * User A generates a Key Pair        */       KeyPairGenerator kpg =         KeyPairGenerator.getInstance("DH");       /*        * Initializes based on Key Length        */       kpg.initialize(bitLength);       System.out.println("A-> Generating Keys....");       System.out.println();       KeyPair kp = kpg.generateKeyPair();       /*        * Create the DH public key spec        */       DHParameterSpec kspec =         ((DHPublicKey) kp.getPublic()).getParams();       /*        * Get the G, P, and public key        * to distribute        */       g     = kspec.getG();       p     = kspec.getP();       userA = kp.getPublic().getEncoded();       /*        * Print out public key values        */       System.out.println();       System.out.println("A->G Value**********************");       System.out.println(g);       System.out.println();       System.out.println("A->P Value**********************");       System.out.println(p);       System.out.println();       System.out         .println("A->Public Key**********************");       System.out.println(userA);       notifyAll();       /*        * Do the KeyAgreement        */       KeyAgreement ka = KeyAgreement.getInstance("DH");       ka.init(kp.getPrivate());       /*        * Actually getting Key from M        */       while (userBfromM == null)        {         wait();       }       System.out.println("A->Got Public Key from B?.......");       System.out.println(userBfromM);        System.out.println();       /*        * Implement the Key Agreement        */       KeyFactory         kf       =         KeyFactory.getInstance("DH");       X509EncodedKeySpec x509Spec =         new X509EncodedKeySpec(userBfromM);       PublicKey          pk       =         kf.generatePublic(x509Spec);       ka.doPhase(pk, true);       /*        * Implement the Key Agreement        */       byte             secret[] = ka.generateSecret();       SecretKeyFactory skf      =         SecretKeyFactory.getInstance("DES");       /*        * Send a DES Cipher to B        * M will actually pick it up and translate it        */       DESKeySpec desSpec   = new DESKeySpec(secret);       SecretKey  secretKey = skf.generateSecret(desSpec);       Cipher     c         =         Cipher.getInstance("DES/ECB/PKCS5Padding");       c.init(Cipher.ENCRYPT_MODE, secretKey);       ciphertext_from_A =         c.doFinal("How are you B?".getBytes());       notifyAll();     }     catch (Exception e)      {       e.printStackTrace();     }   }       /**    * Method doUserB    */   public synchronized void doUserB()    {     try      {       System.out.println("B->Starting User....");       System.out.println();       while (userAfromM == null)        {         wait();       }       System.out.println();       System.out         .println("B->User A's Public?**********************");       System.out.println(userAfromM);       System.out         .println("B->User A's G Value?**********************");       System.out.println(g);       System.out.println();       System.out         .println("B->User A's P Value?**********************");       System.out.println(p);       /*        * Generate a Key Pair        * based on the p and g received        */       KeyPairGenerator kpg    =         KeyPairGenerator.getInstance("DH");       DHParameterSpec  dhSpec = new DHParameterSpec(p, g);       kpg.initialize(dhSpec);       KeyPair kp = kpg.generateKeyPair();       /*        * Distribute Public Key        */       userB = kp.getPublic().getEncoded();       System.out.println();       System.out         .println("B->Public Key**********************");       System.out.println(userB);       notifyAll();       /*        * Key Agreement        */       KeyAgreement ka = KeyAgreement.getInstance("DH");       ka.init(kp.getPrivate());       /*        * Secret Key Exchange        * from M        */       KeyFactory         kf       =         KeyFactory.getInstance("DH");       X509EncodedKeySpec x509Spec =         new X509EncodedKeySpec(userAfromM);       PublicKey          pk       =         kf.generatePublic(x509Spec);       ka.doPhase(pk, true);       /*        * Distribute Public Key        */       byte secret[] = ka.generateSecret();       /*        * Decrypt message, thought to be from A        * Actually from B        */       SecretKeyFactory skf       =         SecretKeyFactory.getInstance("DES");       DESKeySpec       desSpec   = new DESKeySpec(secret);       SecretKey        secretKey = skf.generateSecret(desSpec);       Cipher           c         =         Cipher.getInstance("DES/ECB/PKCS5Padding");       c.init(Cipher.DECRYPT_MODE, secretKey);       while (ciphertext_from_M == null)        {         wait();       }       byte plaintext[] = c.doFinal(ciphertext_from_M);       System.out.println("B->Got Cipher->"                          + new String(plaintext));     }     catch (Exception e)      {       e.printStackTrace();     }   }       /**    * Method doUserM    */   public synchronized void doUserM()    {     try      {       System.out.println("M->Starting User....");       /*        * Wait for User A        */       while (userA == null)        {         wait();       }       System.out.println();       System.out.println("M->A Public Key....");       System.out.println(userA);       System.out.println("M->A's P....");       System.out.println(p);        System.out.println();       System.out.println("M->A's G....");       System.out.println(g);       /*        * Generate a Key pair based on A        */       KeyPairGenerator kpg_from_A    =         KeyPairGenerator.getInstance("DH");       DHParameterSpec  dhSpec_from_A = new DHParameterSpec(p,                                          g);       kpg_from_A.initialize(dhSpec_from_A);       System.out.println("M->Generating a Key from A....");       KeyPair kp_from_A = kpg_from_A.generateKeyPair();       userBfromM = kp_from_A.getPublic().getEncoded();       System.out.println();       System.out.println(         "M->Sending fake B Public Key to A*********************");       System.out.println(userBfromM);       notifyAll();       /*        * Generate a 512 bit Prime to pass to B        * with new  p and g        */       SecureRandom rnd = new SecureRandom();       p = BigInteger.probablePrime(bitLength, rnd);       g = BigInteger.probablePrime(bitLength, rnd);       System.out.println();       System.out         .println("M->New p to B *********************");       System.out.println(p);       System.out.println();       System.out         .println("M->New g to B *********************");       System.out.println(g);       System.out.println();       /*        * Generate a Key pair based on B        */       KeyPairGenerator kpg_to_B    =         KeyPairGenerator.getInstance("DH");       DHParameterSpec  dhSpec_to_B = new DHParameterSpec(p, g);       kpg_to_B.initialize(dhSpec_to_B);       System.out.println("M->Generated a key to B....");       KeyPair kp_to_B = kpg_to_B.generateKeyPair();       userAfromM = kp_to_B.getPublic().getEncoded();       System.out.println();       System.out.println(         "M->Sending fake A Public Key to B*********************");       System.out.println(userAfromM);       notifyAll();       /*        * Wait for B's distribution        */       while (userB == null)        {         wait();       }       System.out.println();       System.out.println("M->B's Public Key....");       System.out.println(userB);       System.out.println();       /*        * Key Agreement between A and M        */       KeyAgreement ka_from_A = KeyAgreement.getInstance("DH");       ka_from_A.init(kp_from_A.getPrivate());       KeyFactory         kf_from_A       =         KeyFactory.getInstance("DH");       X509EncodedKeySpec x509Spec_from_A =         new X509EncodedKeySpec(userA);        PublicKey          pk_from_A       =         kf_from_A.generatePublic(x509Spec_from_A);       ka_from_A.doPhase(pk_from_A, true);       byte secret_from_A[] = ka_from_A.generateSecret();       /*        * Getting cipher text from A        */       while (ciphertext_from_A == null)        {         wait();       }       /*        * Decrypting A's Message        */       SecretKeyFactory skf_from_A     =         SecretKeyFactory.getInstance("DES");       DESKeySpec       desSpec_from_A =         new DESKeySpec(secret_from_A);       SecretKey        key_from_A     =         skf_from_A.generateSecret(desSpec_from_A);       Cipher           c_from_A       =         Cipher.getInstance("DES/ECB/PKCS5Padding");       c_from_A.init(Cipher.DECRYPT_MODE, key_from_A);       byte plaintext[] = c_from_A.doFinal(ciphertext_from_A);       System.out.println("M->Got Cipher from A->"                          + new String(plaintext));       /*        * Key Agreement between B and M        */       KeyAgreement ka_to_B = KeyAgreement.getInstance("DH");       ka_to_B.init(kp_to_B.getPrivate());       KeyFactory         kf_to_B       =         KeyFactory.getInstance("DH");       X509EncodedKeySpec x509Spec_to_B =         new X509EncodedKeySpec(userB);        PublicKey          pk_to_B       =         kf_to_B.generatePublic(x509Spec_to_B);       ka_to_B.doPhase(pk_to_B, true);       byte secret_to_B[] = ka_to_B.generateSecret();           /*        * M is sending B a cipher message        */       SecretKeyFactory skf_to_B     =         SecretKeyFactory.getInstance("DES");       DESKeySpec       desSpec_to_B =         new DESKeySpec(secret_to_B);       SecretKey        key_to_B     =         skf_to_B.generateSecret(desSpec_to_B);       Cipher           c_to_B       =         Cipher.getInstance("DES/ECB/PKCS5Padding");       c_to_B.init(Cipher.ENCRYPT_MODE, key_to_B);       System.out.println();       System.out.println(         "M->Sending different Cipher to B->Are you sure that I am A?");       ciphertext_from_M =         c_to_B.doFinal("Are you sure that I am A?".getBytes());       notifyAll();     }     catch (Exception e)      {       e.printStackTrace();     }   } } 
end example
 

Listing 4-11 demonstrates a multithreaded approach using the javax.crypto.KeyAgreement class that will pass the shared secret key to the other user. Network implementations of key exchange will be explored in a later chapter. Notice that User M receives the p , g , and key information from User A and modifies it before sending it to User B. The biggest weakness of the DH algorithm is the man-in-the-middle attack. To compensate for it, another algorithm evolved, which is called the RSA algorithm, to prevent the man-in-the-middle attack.

Cross-Reference  

Chapter 21 discusses network security in more detail.

  


Java Security Solutions
Java Security Solutions
ISBN: 0764549286
EAN: 2147483647
Year: 2001
Pages: 222

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net