/*
* This file is part of "MidpSSH".
*
* This file was greatly adapted from Java Secure Channel (www.jcraft.com/jsch/) for
* MidpSSH by Karl von Randow
*
* Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
* INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package ssh.v2;
import java.util.Random;
public class DHKeyExchange {
public static final String SSH_DSS = "ssh-dss";
public static final BigInteger g = new BigInteger("2", 16);
// public static final BigInteger g = new BigInteger(new byte[] { 2 });
public static final BigInteger p = new BigInteger("ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff", 16);
// public static final BigInteger p = new BigInteger(new byte[] { (byte) 0x00, (byte) 0xFF, (byte) 0xFF,
// (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
// (byte) 0xFF, (byte) 0xC9, (byte) 0x0F, (byte) 0xDA, (byte) 0xA2,
// (byte) 0x21, (byte) 0x68, (byte) 0xC2, (byte) 0x34, (byte) 0xC4,
// (byte) 0xC6, (byte) 0x62, (byte) 0x8B, (byte) 0x80, (byte) 0xDC,
// (byte) 0x1C, (byte) 0xD1, (byte) 0x29, (byte) 0x02, (byte) 0x4E,
// (byte) 0x08, (byte) 0x8A, (byte) 0x67, (byte) 0xCC, (byte) 0x74,
// (byte) 0x02, (byte) 0x0B, (byte) 0xBE, (byte) 0xA6, (byte) 0x3B,
// (byte) 0x13, (byte) 0x9B, (byte) 0x22, (byte) 0x51, (byte) 0x4A,
// (byte) 0x08, (byte) 0x79, (byte) 0x8E, (byte) 0x34, (byte) 0x04,
// (byte) 0xDD, (byte) 0xEF, (byte) 0x95, (byte) 0x19, (byte) 0xB3,
// (byte) 0xCD, (byte) 0x3A, (byte) 0x43, (byte) 0x1B, (byte) 0x30,
// (byte) 0x2B, (byte) 0x0A, (byte) 0x6D, (byte) 0xF2, (byte) 0x5F,
// (byte) 0x14, (byte) 0x37, (byte) 0x4F, (byte) 0xE1, (byte) 0x35,
// (byte) 0x6D, (byte) 0x6D, (byte) 0x51, (byte) 0xC2, (byte) 0x45,
// (byte) 0xE4, (byte) 0x85, (byte) 0xB5, (byte) 0x76, (byte) 0x62,
// (byte) 0x5E, (byte) 0x7E, (byte) 0xC6, (byte) 0xF4, (byte) 0x4C,
// (byte) 0x42, (byte) 0xE9, (byte) 0xA6, (byte) 0x37, (byte) 0xED,
// (byte) 0x6B, (byte) 0x0B, (byte) 0xFF, (byte) 0x5C, (byte) 0xB6,
// (byte) 0xF4, (byte) 0x06, (byte) 0xB7, (byte) 0xED, (byte) 0xEE,
// (byte) 0x38, (byte) 0x6B, (byte) 0xFB, (byte) 0x5A, (byte) 0x89,
// (byte) 0x9F, (byte) 0xA5, (byte) 0xAE, (byte) 0x9F, (byte) 0x24,
// (byte) 0x11, (byte) 0x7C, (byte) 0x4B, (byte) 0x1F, (byte) 0xE6,
// (byte) 0x49, (byte) 0x28, (byte) 0x66, (byte) 0x51, (byte) 0xEC,
// (byte) 0xE6, (byte) 0x53, (byte) 0x81, (byte) 0xFF, (byte) 0xFF,
// (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
// (byte) 0xFF });
public byte[] V_S;
public byte[] V_C;
public byte[] I_S;
public byte[] I_C;
public byte[] H;
private byte[] e;
public byte[] K;
private BigInteger x, y;
public String keyalg;
public DHKeyExchange(int qLength) {
BigInteger[] keys = generateKeyPair(qLength);
x = keys[0];
y = keys[1];
}
public DHKeyExchange(byte[] x_array, byte[] y_array) {
x = new BigInteger(x_array);
y = new BigInteger(y_array);
}
public byte[] getE() {
if (e == null) {
e = y.toByteArray();
}
return e;
}
public static BigInteger[] generateKeyPair(int qLength) {
qLength = Math.min(qLength, p.bitLength() - 1 - 1);
//System.out.println( "Generating private key" );
//
// calculate the private key
//
BigInteger x = new BigInteger(qLength, new Random());
//System.out.println( "PRIVATE KEY=" + this.x );
//System.out.println( "Generating public key" );
//
// calculate the public key.
//
BigInteger y = g.modPow(x, p);
//System.out.println( "PUBLIC KEY=" + this.y );
//System.out.println( "Generated both keys" );
return new BigInteger[] { x, y };
}
public static byte[][] generateKeyPairBytes(int qLength) {
BigInteger[] keys = generateKeyPair(qLength);
return new byte[][] { keys[0].toByteArray(), keys[1].toByteArray() };
}
/**
*
* @param K_S
* @param f
* @param r
* part 1 of sig of H
* @param s
* part 2 of sig of H
* @return
* @throws Exception
*/
public boolean next(byte[] K_S, byte[] f, byte[] sig_of_h) {
// K_S is server_key_blob, which includes ....
// string ssh-dss
// impint p of dsa
// impint q of dsa
// impint g of dsa
// impint pub_key of dsa
//K = calculateAgreement( new BigInteger( f ) ).toByteArray();
K = new BigInteger(f).modPow(x, p).toByteArray();
//The hash H is computed as the HASH hash of the concatenation
// of the
//following:
// string V_C, the client's version string (CR and NL excluded)
// string V_S, the server's version string (CR and NL excluded)
// string I_C, the payload of the client's SSH_MSG_KEXINIT
// string I_S, the payload of the server's SSH_MSG_KEXINIT
// string K_S, the host key
// mpint e, exchange value sent by the client
// mpint f, exchange value sent by the server
// mpint K, the shared secret
// This value is called the exchange hash, and it is used to
// authenti-
// cate the key exchange.
SshPacket2 buf = new SshPacket2();
buf.putString(V_C);
buf.putString(V_S);
buf.putString(I_C);
buf.putString(I_S);
buf.putString(K_S);
buf.putMpInt(e);
buf.putMpInt(f);
buf.putMpInt(K);
byte[] foo = buf.getData();
SHA1Digest sha = new SHA1Digest();
sha.update(foo, 0, foo.length);
H = new byte[sha.getDigestSize()];
sha.doFinal(H, 0);
SshPacket2 pp = new SshPacket2( null );
pp.putBytes( K_S );
keyalg = pp.getString();
boolean result;
if ( keyalg.equals(SSH_DSS) ) {
byte [] p = pp.getByteString();
byte [] q = pp.getByteString();
byte [] g = pp.getByteString();
byte [] y = pp.getByteString();
result = verifyDSASignature(H, sig_of_h, new BigInteger(y), new BigInteger(p),
new BigInteger(q), new BigInteger(g));
}
else {
//System.out.println("unknow alg");
result = false;
}
return result;
}
public static boolean verifyDSASignature(byte[] message, byte[] sig, BigInteger y,
BigInteger p, BigInteger q, BigInteger g) {
SshPacket2 buf = new SshPacket2();
buf.putBytes(sig);
buf.getByteString(); // algorithm
byte[] blob = buf.getByteString();
int rslen = blob.length / 2;
byte[] tmp = new byte[rslen];
tmp[0] = 0;
System.arraycopy(blob, 0, tmp, 0, rslen);
BigInteger r = new BigInteger(1, tmp);
System.arraycopy(blob, rslen, tmp, 0, rslen);
BigInteger s = new BigInteger(1, tmp);
//boolean verifySignature(byte[] message, BigInteger r, BigInteger s)
SHA1Digest digest = new SHA1Digest();
digest.update(message, 0, message.length);
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
message = hash;
BigInteger m = new BigInteger(1, message);
BigInteger zero = BigInteger.valueOf(0);
if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0) {
return false;
}
if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0) {
return false;
}
BigInteger w = s.modInverse(q);
BigInteger u1 = m.multiply(w).mod(q);
BigInteger u2 = r.multiply(w).mod(q);
u1 = g.modPow(u1, p);
u2 = y.modPow(u2, p);
BigInteger v = u1.multiply(u2).mod(p).mod(q);
return v.equals(r);
}
}