1/*
2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
3 * Please refer to the LICENSE.txt for licensing details.
4 */
5package ch.ethz.ssh2.crypto.dh;
6
7import java.math.BigInteger;
8import java.security.SecureRandom;
9
10import ch.ethz.ssh2.DHGexParameters;
11import ch.ethz.ssh2.crypto.digest.HashForSSH2Types;
12
13/**
14 * DhGroupExchange.
15 *
16 * @author Christian Plattner
17 * @version 2.50, 03/15/10
18 */
19public class DhGroupExchange
20{
21	/* Given by the standard */
22
23	private BigInteger p;
24	private BigInteger g;
25
26	/* Client public and private */
27
28	private BigInteger e;
29	private BigInteger x;
30
31	/* Server public */
32
33	private BigInteger f;
34
35	/* Shared secret */
36
37	private BigInteger k;
38
39	public DhGroupExchange(BigInteger p, BigInteger g)
40	{
41		this.p = p;
42		this.g = g;
43	}
44
45	public void init(SecureRandom rnd)
46	{
47		k = null;
48
49		x = new BigInteger(p.bitLength() - 1, rnd);
50		e = g.modPow(x, p);
51	}
52
53	/**
54	 * @return Returns the e.
55	 */
56	public BigInteger getE()
57	{
58		if (e == null)
59			throw new IllegalStateException("Not initialized!");
60
61		return e;
62	}
63
64	/**
65	 * @return Returns the shared secret k.
66	 */
67	public BigInteger getK()
68	{
69		if (k == null)
70			throw new IllegalStateException("Shared secret not yet known, need f first!");
71
72		return k;
73	}
74
75	/**
76	 * Sets f and calculates the shared secret.
77	 */
78	public void setF(BigInteger f)
79	{
80		if (e == null)
81			throw new IllegalStateException("Not initialized!");
82
83		BigInteger zero = BigInteger.valueOf(0);
84
85		if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0)
86			throw new IllegalArgumentException("Invalid f specified!");
87
88		this.f = f;
89		this.k = f.modPow(x, p);
90	}
91
92	public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload,
93			byte[] serverKexPayload, byte[] hostKey, DHGexParameters para)
94	{
95		HashForSSH2Types hash = new HashForSSH2Types("SHA1");
96
97		hash.updateByteString(clientversion);
98		hash.updateByteString(serverversion);
99		hash.updateByteString(clientKexPayload);
100		hash.updateByteString(serverKexPayload);
101		hash.updateByteString(hostKey);
102		if (para.getMin_group_len() > 0)
103			hash.updateUINT32(para.getMin_group_len());
104		hash.updateUINT32(para.getPref_group_len());
105		if (para.getMax_group_len() > 0)
106			hash.updateUINT32(para.getMax_group_len());
107		hash.updateBigInt(p);
108		hash.updateBigInt(g);
109		hash.updateBigInt(e);
110		hash.updateBigInt(f);
111		hash.updateBigInt(k);
112
113		return hash.getDigest();
114	}
115}
116