view src/com/trilead/ssh2/crypto/dh/DhExchange.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children
line wrap: on
line source

/**
 *
 */
package com.trilead.ssh2.crypto.dh;

import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;

/**
 * @author kenny
 *
 */
public class DhExchange extends GenericDhExchange {

    /* Given by the standard */

    private static final BigInteger P1 = new BigInteger(
        "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
        + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
        + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
        + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
        + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
        + "FFFFFFFFFFFFFFFF", 16);

    private static final BigInteger P14 = new BigInteger(
        "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
        + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
        + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
        + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
        + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
        + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
        + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
        + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
        + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
        + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
        + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16);

    private static final BigInteger G = BigInteger.valueOf(2);

    /* Client public and private */

    private DHPrivateKey clientPrivate;
    private DHPublicKey clientPublic;

    /* Server public */

    private DHPublicKey serverPublic;

    @Override
    public void init(String name) throws IOException {
        final DHParameterSpec spec;

        if ("diffie-hellman-group1-sha1".equals(name)) {
            spec = new DHParameterSpec(P1, G);
        }
        else if ("diffie-hellman-group14-sha1".equals(name)) {
            spec = new DHParameterSpec(P14, G);
        }
        else {
            throw new IllegalArgumentException("Unknown DH group " + name);
        }

        try {
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
            kpg.initialize(spec);
            KeyPair pair = kpg.generateKeyPair();
            clientPrivate = (DHPrivateKey) pair.getPrivate();
            clientPublic = (DHPublicKey) pair.getPublic();
        }
        catch (NoSuchAlgorithmException e) {
            throw(IOException) new IOException("No DH keypair generator").initCause(e);
        }
        catch (InvalidAlgorithmParameterException e) {
            throw(IOException) new IOException("Invalid DH parameters").initCause(e);
        }
    }

    @Override
    public byte[] getE() {
        if (clientPublic == null)
            throw new IllegalStateException("DhExchange not initialized!");

        return clientPublic.getY().toByteArray();
    }

    @Override
    protected byte[] getServerE() {
        if (serverPublic == null)
            throw new IllegalStateException("DhExchange not initialized!");

        return serverPublic.getY().toByteArray();
    }

    @Override
    public void setF(byte[] f) throws IOException {
        if (clientPublic == null)
            throw new IllegalStateException("DhExchange not initialized!");

        final KeyAgreement ka;

        try {
            KeyFactory kf = KeyFactory.getInstance("DH");
            DHParameterSpec params = clientPublic.getParams();
            this.serverPublic = (DHPublicKey) kf.generatePublic(new DHPublicKeySpec(
                                    new BigInteger(f), params.getP(), params.getG()));
            ka = KeyAgreement.getInstance("DH");
            ka.init(clientPrivate);
            ka.doPhase(serverPublic, true);
        }
        catch (NoSuchAlgorithmException e) {
            throw(IOException) new IOException("No DH key agreement method").initCause(e);
        }
        catch (InvalidKeyException e) {
            throw(IOException) new IOException("Invalid DH key").initCause(e);
        }
        catch (InvalidKeySpecException e) {
            throw(IOException) new IOException("Invalid DH key").initCause(e);
        }

        sharedSecret = new BigInteger(ka.generateSecret());
    }

    @Override
    public String getHashAlgo() {
        return "SHA1";
    }
}