Home | History | Annotate | Download | only in dh
      1 /*
      2  * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
      3  * Please refer to the LICENSE.txt for licensing details.
      4  */
      5 package ch.ethz.ssh2.crypto.dh;
      6 
      7 import java.math.BigInteger;
      8 import java.security.SecureRandom;
      9 
     10 import ch.ethz.ssh2.crypto.digest.HashForSSH2Types;
     11 import ch.ethz.ssh2.log.Logger;
     12 import ch.ethz.ssh2.util.StringEncoder;
     13 
     14 /**
     15  * @author Christian Plattner
     16  * @version $Id: DhExchange.java 41 2011-06-02 10:36:41Z dkocher (at) sudo.ch $
     17  */
     18 public class DhExchange
     19 {
     20 	private static final Logger log = Logger.getLogger(DhExchange.class);
     21 
     22 	/* Given by the standard */
     23 
     24 	static final BigInteger p1, p14;
     25 	static final BigInteger g;
     26 
     27 	BigInteger p;
     28 
     29 	/* Client public and private */
     30 
     31 	BigInteger e;
     32 	BigInteger x;
     33 
     34 	/* Server public */
     35 
     36 	BigInteger f;
     37 
     38 	/* Shared secret */
     39 
     40 	BigInteger k;
     41 
     42 	static
     43 	{
     44 		final String p1_string = "17976931348623159077083915679378745319786029604875"
     45 				+ "60117064444236841971802161585193689478337958649255415021805654859805036464"
     46 				+ "40548199239100050792877003355816639229553136239076508735759914822574862575"
     47 				+ "00742530207744771258955095793777842444242661733472762929938766870920560605"
     48 				+ "0270810842907692932019128194467627007";
     49 
     50 		final String p14_string = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129"
     51 				+ "024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0"
     52 				+ "A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB"
     53 				+ "6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A"
     54 				+ "163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208"
     55 				+ "552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36C"
     56 				+ "E3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558171"
     57 				+ "83995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF";
     58 
     59 		p1 = new BigInteger(p1_string);
     60 		p14 = new BigInteger(p14_string, 16);
     61 		g = new BigInteger("2");
     62 	}
     63 
     64 	public DhExchange()
     65 	{
     66 	}
     67 
     68 	public void init(int group, SecureRandom rnd)
     69 	{
     70 		k = null;
     71 
     72 		if (group == 1)
     73 			p = p1;
     74 		else if (group == 14)
     75 			p = p14;
     76 		else
     77 			throw new IllegalArgumentException("Unknown DH group " + group);
     78 
     79 		x = new BigInteger(p.bitLength() - 1, rnd);
     80 
     81 		e = g.modPow(x, p);
     82 	}
     83 
     84 	/**
     85 	 * @return Returns the e.
     86 	 * @throws IllegalStateException
     87 	 */
     88 	public BigInteger getE()
     89 	{
     90 		if (e == null)
     91 			throw new IllegalStateException("DhDsaExchange not initialized!");
     92 
     93 		return e;
     94 	}
     95 
     96 	/**
     97 	 * @return Returns the shared secret k.
     98 	 * @throws IllegalStateException
     99 	 */
    100 	public BigInteger getK()
    101 	{
    102 		if (k == null)
    103 			throw new IllegalStateException("Shared secret not yet known, need f first!");
    104 
    105 		return k;
    106 	}
    107 
    108 	/**
    109 	 * @param f
    110 	 */
    111 	public void setF(BigInteger f)
    112 	{
    113 		if (e == null)
    114 			throw new IllegalStateException("DhDsaExchange not initialized!");
    115 
    116 		BigInteger zero = BigInteger.valueOf(0);
    117 
    118 		if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0)
    119 			throw new IllegalArgumentException("Invalid f specified!");
    120 
    121 		this.f = f;
    122 		this.k = f.modPow(x, p);
    123 	}
    124 
    125 	public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload,
    126 							 byte[] serverKexPayload, byte[] hostKey)
    127 	{
    128 		HashForSSH2Types hash = new HashForSSH2Types("SHA1");
    129 
    130 		if (log.isInfoEnabled())
    131 		{
    132 			log.info("Client: '" + StringEncoder.GetString(clientversion) + "'");
    133 		    log.info("Server: '" + StringEncoder.GetString(serverversion) + "'");
    134 		}
    135 		hash.updateByteString(clientversion);
    136 		hash.updateByteString(serverversion);
    137 		hash.updateByteString(clientKexPayload);
    138 		hash.updateByteString(serverKexPayload);
    139 		hash.updateByteString(hostKey);
    140 		hash.updateBigInt(e);
    141 		hash.updateBigInt(f);
    142 		hash.updateBigInt(k);
    143 
    144 		return hash.getDigest();
    145 	}
    146 }
    147