All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sshtools.client.components.DiffieHellmanEcdh Maven / Gradle / Ivy

The newest version!
package com.sshtools.client.components;

/*-
 * #%L
 * Client API
 * %%
 * Copyright (C) 2002 - 2024 JADAPTIVE Limited
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;

import javax.crypto.KeyAgreement;

import com.sshtools.client.SshClientContext;
import com.sshtools.client.SshKeyExchangeClient;
import com.sshtools.common.logger.Log;
import com.sshtools.common.ssh.SecurityLevel;
import com.sshtools.common.ssh.SshException;
import com.sshtools.common.ssh.SshIOException;
import com.sshtools.common.ssh.components.ComponentManager;
import com.sshtools.common.ssh.components.Digest;
import com.sshtools.common.ssh.components.SshPrivateKey;
import com.sshtools.common.ssh.components.SshPublicKey;
import com.sshtools.common.ssh.components.jce.ECUtils;
import com.sshtools.common.ssh.components.jce.JCEAlgorithms;
import com.sshtools.common.ssh.components.jce.JCEProvider;
import com.sshtools.common.sshd.SshMessage;
import com.sshtools.common.util.ByteArrayReader;
import com.sshtools.synergy.ssh.SshTransport;
import com.sshtools.synergy.ssh.components.SshKeyExchange;

public abstract class DiffieHellmanEcdh extends SshKeyExchangeClient implements
		SshKeyExchange {

	public static final int SSH_MSG_KEX_ECDH_INIT = 30;
	public static final int SSH_MSG_KEX_ECDH_REPLY = 31;

	String name;
	String curve;

	byte[] Q_S;
	byte[] Q_C;

	String clientId;
	String serverId;
	byte[] clientKexInit;
	byte[] serverKexInit;

	SshPrivateKey prvkey;
	SshPublicKey pubkey;
	
	KeyPairGenerator keyGen;
	KeyAgreement keyAgreement;
	KeyPair keyPair;
	
	protected DiffieHellmanEcdh(String name, String curve, String hashAlgorithm, SecurityLevel securityLevel, int priority) {
		super(hashAlgorithm, securityLevel, priority);
		this.name = name;
		this.curve = curve;
	}

	@Override
	public String getAlgorithm() {
		return name;
	}

	protected void calculateExchangeHash() throws SshException {
		Digest hash = (Digest) ComponentManager.getDefaultInstance()
				.supportedDigests().getInstance(getHashAlgorithm());

		// The local software version comments
		hash.putString(clientId);

		// The remote software version comments
		hash.putString(serverId);

		// The local kex init payload
		hash.putInt(clientKexInit.length);
		hash.putBytes(clientKexInit);

		// The remote kex init payload
		hash.putInt(serverKexInit.length);
		hash.putBytes(serverKexInit);

		// The host key
		hash.putInt(hostKey.length);
		hash.putBytes(hostKey);

		hash.putInt(Q_C.length);
		hash.putBytes(Q_C);

		hash.putInt(Q_S.length);
		hash.putBytes(Q_S);

		// The diffie hellman k value
		hash.putBigInteger(secret);

		// Do the final output
		exchangeHash = hash.doFinal();
	}

	@Override
	public void init(SshTransport transport, String clientId, String serverId,
			byte[] clientKexInit, byte[] serverKexInit, SshPrivateKey prvkey, SshPublicKey pubkey,
			boolean firstPacketFollows, boolean useFirstPacket) throws IOException, SshException {

		try {
			this.transport = transport;
			this.clientId = clientId;
			this.serverId = serverId;
			this.clientKexInit = clientKexInit;
			this.serverKexInit = serverKexInit;
			this.firstPacketFollows = firstPacketFollows;
			this.useFirstPacket = useFirstPacket;


			initCrypto();
			
			ECPublicKey ec = (ECPublicKey) keyPair.getPublic();
			Q_C = ECUtils.toByteArray(ec.getW(), ec.getParams().getCurve());
			
			transport.postMessage(new SshMessage() {
		          public boolean writeMessageIntoBuffer(ByteBuffer buf) {

					buf.put((byte) SSH_MSG_KEX_ECDH_INIT);
					buf.putInt(Q_C.length);
					buf.put(Q_C);

					return true;
				}
		        
				public void messageSent(Long sequenceNo) {
					if(Log.isDebugEnabled())
						Log.debug("Sent SSH_MSG_KEX_ECDH_INIT");
				}
			}, true);

		} catch (SshException e) {
			throw new SshIOException(e);
		} catch(Exception e) {
			throw new SshException(e, SshException.KEY_EXCHANGE_FAILED);
		}

	}

	@Override
	public boolean processMessage(byte[] msg) throws SshException, IOException {

		if (msg[0] != SSH_MSG_KEX_ECDH_REPLY) {
			return false;
		}

		ByteArrayReader reply = new ByteArrayReader(msg, 1, msg.length-1);
		
		try {
			hostKey = reply.readBinaryString();
			Q_S = reply.readBinaryString();
			signature = reply.readBinaryString();
			
			keyAgreement.doPhase(ECUtils.decodeKey(Q_S, curve), true);
			
			byte[] tmp = keyAgreement.generateSecret();
	        if((tmp[0] & 0x80)==0x80) {
	        	byte[] tmp2 = new byte[tmp.length+1];
	        	System.arraycopy(tmp, 0, tmp2, 1, tmp.length);
	        	tmp = tmp2;
	        }
	        
	        // Calculate diffe hellman k value
	        secret = new BigInteger(tmp);
	        
			calculateExchangeHash();

			transport.sendNewKeys();

			return true;
		} catch(Exception e) { 
			throw new SshException(e, SshException.KEY_EXCHANGE_FAILED);
		} finally {
			reply.close();
		}


	}

	@Override
	public String getProvider() {
		return keyGen.getProvider().getName();
	}
	
	private void initCrypto() throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, SshException {
		ComponentManager.getInstance().supportedDigests().getInstance(getHashAlgorithm());
		
		keyGen = JCEProvider.getProviderForAlgorithm(JCEProvider.getECDSAAlgorithmName())==null ? 
				KeyPairGenerator.getInstance(JCEProvider.getECDSAAlgorithmName()) : 
					KeyPairGenerator.getInstance(JCEProvider.getECDSAAlgorithmName(), 
							JCEProvider.getProviderForAlgorithm(JCEProvider.getECDSAAlgorithmName()));
		keyAgreement = JCEProvider.getProviderForAlgorithm(JCEAlgorithms.JCE_ECDH)==null ? 
				KeyAgreement.getInstance(JCEAlgorithms.JCE_ECDH) : 
					KeyAgreement.getInstance(JCEAlgorithms.JCE_ECDH, 
							JCEProvider.getProviderForAlgorithm(JCEAlgorithms.JCE_ECDH));

		
		ECGenParameterSpec namedSpec = new ECGenParameterSpec(curve);
		keyGen.initialize(namedSpec);
		keyPair = keyGen.generateKeyPair();
		keyAgreement.init(keyPair.getPrivate());
	}

	@Override
	public void test() throws IOException, SshException {
		try {
			initCrypto();
		} catch (Throwable e) {
			throw new IllegalStateException(e.getMessage(), e);
		}
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy