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

org.pcap4j.packet.Ssh2KexInitPacket Maven / Gradle / Ivy

/*_##########################################################################
  _##
  _##  Copyright (C) 2014  Pcap4J.org
  _##
  _##########################################################################
*/

package org.pcap4j.packet;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.pcap4j.packet.namednumber.Ssh2MessageNumber;
import org.pcap4j.util.ByteArrays;

/**
 * @author Kaito Yamada
 * @since pcap4j 1.0.1
 */
public final class Ssh2KexInitPacket extends AbstractPacket {

  /** */
  private static final long serialVersionUID = -2424080361918022468L;

  private final Ssh2KexInitHeader header;

  /**
   * A static factory method. This method validates the arguments by {@link
   * ByteArrays#validateBounds(byte[], int, int)}, which may throw exceptions undocumented here.
   *
   * @param rawData rawData
   * @param offset offset
   * @param length length
   * @return a new Ssh2KexInitPacket object.
   * @throws IllegalRawDataException if parsing the raw data fails.
   */
  public static Ssh2KexInitPacket newPacket(byte[] rawData, int offset, int length)
      throws IllegalRawDataException {
    ByteArrays.validateBounds(rawData, offset, length);
    return new Ssh2KexInitPacket(rawData, offset, length);
  }

  private Ssh2KexInitPacket(byte[] rawData, int offset, int length) throws IllegalRawDataException {
    this.header = new Ssh2KexInitHeader(rawData, offset, length);
  }

  private Ssh2KexInitPacket(Builder builder) {
    if (builder == null
        || builder.cookie == null
        || builder.kexAlgorithms == null
        || builder.serverHostKeyAlgorithms == null
        || builder.encryptionAlgorithmsClientToServer == null
        || builder.encryptionAlgorithmsServerToClient == null
        || builder.macAlgorithmsClientToServer == null
        || builder.macAlgorithmsServerToClient == null
        || builder.compressionAlgorithmsClientToServer == null
        || builder.compressionAlgorithmsServerToClient == null
        || builder.languagesClientToServer == null
        || builder.languagesServerToClient == null
        || builder.firstKexPacketFollows == null) {
      StringBuilder sb = new StringBuilder();
      sb.append("builder: ")
          .append(builder)
          .append(" builder.cookie: ")
          .append(builder.cookie)
          .append(" builder.kexAlgorithms: ")
          .append(builder.kexAlgorithms)
          .append(" builder.serverHostKeyAlgorithms: ")
          .append(builder.serverHostKeyAlgorithms)
          .append(" builder.encryptionAlgorithmsClientToServer: ")
          .append(builder.encryptionAlgorithmsClientToServer)
          .append(" builder.encryptionAlgorithmsServerToClient: ")
          .append(builder.encryptionAlgorithmsServerToClient)
          .append(" builder.macAlgorithmsClientToServer: ")
          .append(builder.macAlgorithmsClientToServer)
          .append(" builder.macAlgorithmsServerToClient: ")
          .append(builder.macAlgorithmsServerToClient)
          .append(" builder.compressionAlgorithmsClientToServer: ")
          .append(builder.compressionAlgorithmsClientToServer)
          .append(" builder.compressionAlgorithmsServerToClient: ")
          .append(builder.compressionAlgorithmsServerToClient)
          .append(" builder.languagesClientToServer: ")
          .append(builder.languagesClientToServer)
          .append(" builder.languagesServerToClient: ")
          .append(builder.languagesServerToClient)
          .append(" builder.firstKexPacketFollows: ")
          .append(builder.firstKexPacketFollows);
      throw new NullPointerException(sb.toString());
    }

    this.header = new Ssh2KexInitHeader(builder);
  }

  @Override
  public Ssh2KexInitHeader getHeader() {
    return header;
  }

  @Override
  public Builder getBuilder() {
    return new Builder(this);
  }

  /**
   * @author Kaito Yamada
   * @since pcap4j 1.0.1
   */
  public static final class Builder extends AbstractBuilder {

    private byte[] cookie;
    private Ssh2NameList kexAlgorithms;
    private Ssh2NameList serverHostKeyAlgorithms;
    private Ssh2NameList encryptionAlgorithmsClientToServer;
    private Ssh2NameList encryptionAlgorithmsServerToClient;
    private Ssh2NameList macAlgorithmsClientToServer;
    private Ssh2NameList macAlgorithmsServerToClient;
    private Ssh2NameList compressionAlgorithmsClientToServer;
    private Ssh2NameList compressionAlgorithmsServerToClient;
    private Ssh2NameList languagesClientToServer;
    private Ssh2NameList languagesServerToClient;
    private Ssh2Boolean firstKexPacketFollows;
    private int reserved;

    /** */
    public Builder() {}

    private Builder(Ssh2KexInitPacket packet) {
      this.cookie = packet.header.cookie;
      this.kexAlgorithms = packet.header.kexAlgorithms;
      this.serverHostKeyAlgorithms = packet.header.serverHostKeyAlgorithms;
      this.encryptionAlgorithmsClientToServer = packet.header.encryptionAlgorithmsClientToServer;
      this.encryptionAlgorithmsServerToClient = packet.header.encryptionAlgorithmsServerToClient;
      this.macAlgorithmsClientToServer = packet.header.macAlgorithmsClientToServer;
      this.macAlgorithmsServerToClient = packet.header.macAlgorithmsServerToClient;
      this.compressionAlgorithmsClientToServer = packet.header.compressionAlgorithmsClientToServer;
      this.compressionAlgorithmsServerToClient = packet.header.compressionAlgorithmsServerToClient;
      this.languagesClientToServer = packet.header.languagesClientToServer;
      this.languagesServerToClient = packet.header.languagesServerToClient;
      this.firstKexPacketFollows = packet.header.firstKexPacketFollows;
      this.reserved = packet.header.reserved;
    }

    /**
     * @param cookie cookie
     * @return this Builder object for method chaining.
     */
    public Builder cookie(byte[] cookie) {
      this.cookie = cookie;
      return this;
    }

    /**
     * @param kexAlgorithms kexAlgorithms
     * @return this Builder object for method chaining.
     */
    public Builder kexAlgorithms(Ssh2NameList kexAlgorithms) {
      this.kexAlgorithms = kexAlgorithms;
      return this;
    }

    /**
     * @param serverHostKeyAlgorithms serverHostKeyAlgorithms
     * @return this Builder object for method chaining.
     */
    public Builder serverHostKeyAlgorithms(Ssh2NameList serverHostKeyAlgorithms) {
      this.serverHostKeyAlgorithms = serverHostKeyAlgorithms;
      return this;
    }

    /**
     * @param encryptionAlgorithmsClientToServer encryptionAlgorithmsClientToServer
     * @return this Builder object for method chaining.
     */
    public Builder encryptionAlgorithmsClientToServer(
        Ssh2NameList encryptionAlgorithmsClientToServer) {
      this.encryptionAlgorithmsClientToServer = encryptionAlgorithmsClientToServer;
      return this;
    }

    /**
     * @param encryptionAlgorithmsServerToClient encryptionAlgorithmsServerToClient
     * @return this Builder object for method chaining.
     */
    public Builder encryptionAlgorithmsServerToClient(
        Ssh2NameList encryptionAlgorithmsServerToClient) {
      this.encryptionAlgorithmsServerToClient = encryptionAlgorithmsServerToClient;
      return this;
    }

    /**
     * @param macAlgorithmsClientToServer macAlgorithmsClientToServer
     * @return this Builder object for method chaining.
     */
    public Builder macAlgorithmsClientToServer(Ssh2NameList macAlgorithmsClientToServer) {
      this.macAlgorithmsClientToServer = macAlgorithmsClientToServer;
      return this;
    }

    /**
     * @param macAlgorithmsServerToClient macAlgorithmsServerToClient
     * @return this Builder object for method chaining.
     */
    public Builder macAlgorithmsServerToClient(Ssh2NameList macAlgorithmsServerToClient) {
      this.macAlgorithmsServerToClient = macAlgorithmsServerToClient;
      return this;
    }

    /**
     * @param compressionAlgorithmsClientToServer compressionAlgorithmsClientToServer
     * @return this Builder object for method chaining.
     */
    public Builder compressionAlgorithmsClientToServer(
        Ssh2NameList compressionAlgorithmsClientToServer) {
      this.compressionAlgorithmsClientToServer = compressionAlgorithmsClientToServer;
      return this;
    }

    /**
     * @param compressionAlgorithmsServerToClient compressionAlgorithmsServerToClient
     * @return this Builder object for method chaining.
     */
    public Builder compressionAlgorithmsServerToClient(
        Ssh2NameList compressionAlgorithmsServerToClient) {
      this.compressionAlgorithmsServerToClient = compressionAlgorithmsServerToClient;
      return this;
    }

    /**
     * @param languagesClientToServer languagesClientToServer
     * @return this Builder object for method chaining.
     */
    public Builder languagesClientToServer(Ssh2NameList languagesClientToServer) {
      this.languagesClientToServer = languagesClientToServer;
      return this;
    }

    /**
     * @param languagesServerToClient languagesServerToClient
     * @return this Builder object for method chaining.
     */
    public Builder languagesServerToClient(Ssh2NameList languagesServerToClient) {
      this.languagesServerToClient = languagesServerToClient;
      return this;
    }

    /**
     * @param firstKexPacketFollows firstKexPacketFollows
     * @return this Builder object for method chaining.
     */
    public Builder firstKexPacketFollows(Ssh2Boolean firstKexPacketFollows) {
      this.firstKexPacketFollows = firstKexPacketFollows;
      return this;
    }

    /**
     * @param reserved reserved
     * @return this Builder object for method chaining.
     */
    public Builder reserved(int reserved) {
      this.reserved = reserved;
      return this;
    }

    @Override
    public Ssh2KexInitPacket build() {
      return new Ssh2KexInitPacket(this);
    }
  }

  /**
   * @author Kaito Yamada
   * @version pcap4j 1.0.1
   */
  public static final class Ssh2KexInitHeader extends AbstractHeader {

    /*
     * http://tools.ietf.org/html/rfc4253
     *
     * byte         SSH_MSG_KEXINIT
     * byte[16]     cookie (random bytes)
     * name-list    kex_algorithms
     * name-list    server_host_key_algorithms
     * name-list    encryption_algorithms_client_to_server
     * name-list    encryption_algorithms_server_to_client
     * name-list    mac_algorithms_client_to_server
     * name-list    mac_algorithms_server_to_client
     * name-list    compression_algorithms_client_to_server
     * name-list    compression_algorithms_server_to_client
     * name-list    languages_client_to_server
     * name-list    languages_server_to_client
     * boolean      first_kex_packet_follows
     * uint32       0 (reserved for future extension)
     */

    /** */
    private static final long serialVersionUID = -2780304573850816908L;

    private final Ssh2MessageNumber messageNumber = Ssh2MessageNumber.SSH_MSG_KEXINIT;
    private final byte[] cookie;
    private final Ssh2NameList kexAlgorithms;
    private final Ssh2NameList serverHostKeyAlgorithms;
    private final Ssh2NameList encryptionAlgorithmsClientToServer;
    private final Ssh2NameList encryptionAlgorithmsServerToClient;
    private final Ssh2NameList macAlgorithmsClientToServer;
    private final Ssh2NameList macAlgorithmsServerToClient;
    private final Ssh2NameList compressionAlgorithmsClientToServer;
    private final Ssh2NameList compressionAlgorithmsServerToClient;
    private final Ssh2NameList languagesClientToServer;
    private final Ssh2NameList languagesServerToClient;
    private final Ssh2Boolean firstKexPacketFollows;
    private final int reserved;

    private Ssh2KexInitHeader(byte[] rawData, int offset, int length)
        throws IllegalRawDataException {
      if (length < 62) {
        StringBuilder sb = new StringBuilder(120);
        sb.append("The data is too short to build an SSH2 KEX init header. data: ")
            .append(new String(rawData))
            .append(", offset: ")
            .append(offset)
            .append(", length: ")
            .append(length);
        throw new IllegalRawDataException(sb.toString());
      }
      if (!Ssh2MessageNumber.getInstance(rawData[offset])
          .equals(Ssh2MessageNumber.SSH_MSG_KEXINIT)) {
        StringBuilder sb = new StringBuilder(120);
        sb.append("The data is not an SSH2 KEX init message. data: ")
            .append(new String(rawData))
            .append(", offset: ")
            .append(offset)
            .append(", length: ")
            .append(length);
        throw new IllegalRawDataException(sb.toString());
      }

      int currentOffset = 1 + offset;
      int remainingLength = length - 1;
      this.cookie = ByteArrays.getSubArray(rawData, currentOffset, 16);
      currentOffset += cookie.length;
      remainingLength -= cookie.length;
      this.kexAlgorithms = new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += kexAlgorithms.length();
      remainingLength -= kexAlgorithms.length();
      this.serverHostKeyAlgorithms = new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += serverHostKeyAlgorithms.length();
      remainingLength -= serverHostKeyAlgorithms.length();
      this.encryptionAlgorithmsClientToServer =
          new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += encryptionAlgorithmsClientToServer.length();
      remainingLength -= encryptionAlgorithmsClientToServer.length();
      this.encryptionAlgorithmsServerToClient =
          new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += encryptionAlgorithmsClientToServer.length();
      remainingLength -= encryptionAlgorithmsClientToServer.length();
      this.macAlgorithmsClientToServer = new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += macAlgorithmsClientToServer.length();
      remainingLength -= macAlgorithmsClientToServer.length();
      this.macAlgorithmsServerToClient = new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += macAlgorithmsServerToClient.length();
      remainingLength -= macAlgorithmsServerToClient.length();
      this.compressionAlgorithmsClientToServer =
          new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += compressionAlgorithmsClientToServer.length();
      remainingLength -= compressionAlgorithmsClientToServer.length();
      this.compressionAlgorithmsServerToClient =
          new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += compressionAlgorithmsServerToClient.length();
      remainingLength -= compressionAlgorithmsServerToClient.length();
      this.languagesClientToServer = new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += languagesClientToServer.length();
      remainingLength -= languagesClientToServer.length();
      this.languagesServerToClient = new Ssh2NameList(rawData, currentOffset, remainingLength);
      currentOffset += languagesServerToClient.length();
      remainingLength -= languagesServerToClient.length();

      if (remainingLength < 5) {
        StringBuilder sb = new StringBuilder(120);
        sb.append("The data is too short to build an SSH2 KEX init header. data: ")
            .append(new String(rawData))
            .append(", offset: ")
            .append(offset)
            .append(", length: ")
            .append(length);
        throw new IllegalRawDataException(sb.toString());
      }

      this.firstKexPacketFollows = new Ssh2Boolean(rawData[currentOffset]);
      currentOffset += 1;
      this.reserved = ByteArrays.getInt(rawData, currentOffset);
    }

    private Ssh2KexInitHeader(Builder builder) {
      this.cookie = ByteArrays.clone(builder.cookie);
      if (cookie.length != 16) {
        StringBuilder sb = new StringBuilder(100);
        sb.append("cookie length must be 16. builder.cookie: ")
            .append(ByteArrays.toHexString(builder.cookie, " "));
        throw new IllegalArgumentException(sb.toString());
      }
      this.kexAlgorithms = builder.kexAlgorithms;
      this.serverHostKeyAlgorithms = builder.serverHostKeyAlgorithms;
      this.encryptionAlgorithmsClientToServer = builder.encryptionAlgorithmsClientToServer;
      this.encryptionAlgorithmsServerToClient = builder.encryptionAlgorithmsServerToClient;
      this.macAlgorithmsClientToServer = builder.macAlgorithmsClientToServer;
      this.macAlgorithmsServerToClient = builder.macAlgorithmsServerToClient;
      this.compressionAlgorithmsClientToServer = builder.compressionAlgorithmsClientToServer;
      this.compressionAlgorithmsServerToClient = builder.compressionAlgorithmsServerToClient;
      this.languagesClientToServer = builder.languagesClientToServer;
      this.languagesServerToClient = builder.languagesServerToClient;
      this.firstKexPacketFollows = builder.firstKexPacketFollows;
      this.reserved = builder.reserved;
    }

    /** @return messageNumber */
    public Ssh2MessageNumber getMessageNumber() {
      return messageNumber;
    }

    /** @return cookie */
    public byte[] getCookie() {
      return ByteArrays.clone(cookie);
    }

    /** @return kexAlgorithms */
    public Ssh2NameList getKexAlgorithms() {
      return kexAlgorithms;
    }

    /** @return serverHostKeyAlgorithms */
    public Ssh2NameList getServerHostKeyAlgorithms() {
      return serverHostKeyAlgorithms;
    }

    /** @return encryptionAlgorithmsClientToServer */
    public Ssh2NameList getEncryptionAlgorithmsClientToServer() {
      return encryptionAlgorithmsClientToServer;
    }

    /** @return encryptionAlgorithmsServerToClient */
    public Ssh2NameList getEncryptionAlgorithmsServerToClient() {
      return encryptionAlgorithmsServerToClient;
    }

    /** @return macAlgorithmsClientToServer */
    public Ssh2NameList getMacAlgorithmsClientToServer() {
      return macAlgorithmsClientToServer;
    }

    /** @return macAlgorithmsServerToClient */
    public Ssh2NameList getMacAlgorithmsServerToClient() {
      return macAlgorithmsServerToClient;
    }

    /** @return compressionAlgorithmsClientToServer */
    public Ssh2NameList getCompressionAlgorithmsClientToServer() {
      return compressionAlgorithmsClientToServer;
    }

    /** @return compressionAlgorithmsServerToClient */
    public Ssh2NameList getCompressionAlgorithmsServerToClient() {
      return compressionAlgorithmsServerToClient;
    }

    /** @return languagesClientToServer */
    public Ssh2NameList getLanguagesClientToServer() {
      return languagesClientToServer;
    }

    /** @return languagesServerToClient */
    public Ssh2NameList getLanguagesServerToClient() {
      return languagesServerToClient;
    }

    /** @return firstKexPacketFollows */
    public Ssh2Boolean getFirstKexPacketFollows() {
      return firstKexPacketFollows;
    }

    /** @return reserved */
    public int getReserved() {
      return reserved;
    }

    @Override
    protected List getRawFields() {
      List rawFields = new ArrayList();
      rawFields.add(new byte[] {messageNumber.value()});
      rawFields.add(cookie);
      rawFields.add(kexAlgorithms.getRawData());
      rawFields.add(serverHostKeyAlgorithms.getRawData());
      rawFields.add(encryptionAlgorithmsClientToServer.getRawData());
      rawFields.add(encryptionAlgorithmsServerToClient.getRawData());
      rawFields.add(macAlgorithmsClientToServer.getRawData());
      rawFields.add(macAlgorithmsServerToClient.getRawData());
      rawFields.add(compressionAlgorithmsClientToServer.getRawData());
      rawFields.add(compressionAlgorithmsServerToClient.getRawData());
      rawFields.add(languagesClientToServer.getRawData());
      rawFields.add(languagesServerToClient.getRawData());
      rawFields.add(firstKexPacketFollows.getRawData());
      rawFields.add(ByteArrays.toByteArray(reserved));
      return rawFields;
    }

    @Override
    protected int calcLength() {
      return getRawData().length;
    }

    @Override
    protected String buildString() {
      StringBuilder sb = new StringBuilder();
      String ls = System.getProperty("line.separator");

      sb.append("[SSH2 KEX init Header (").append(length()).append(" bytes)]").append(ls);
      sb.append("  Message Number: ").append(messageNumber).append(ls);
      sb.append("  cookie: ").append(ByteArrays.toHexString(cookie, " ")).append(ls);
      sb.append("  kex_algorithms: ").append(kexAlgorithms).append(ls);
      sb.append("  server_host_key_algorithms: ").append(serverHostKeyAlgorithms).append(ls);
      sb.append("  encryption_algorithms_client_to_server: ")
          .append(encryptionAlgorithmsClientToServer)
          .append(ls);
      sb.append("  encryption_algorithms_server_to_client: ")
          .append(encryptionAlgorithmsServerToClient)
          .append(ls);
      sb.append("  mac_algorithms_client_to_server: ")
          .append(macAlgorithmsClientToServer)
          .append(ls);
      sb.append("  mac_algorithms_server_to_client: ")
          .append(macAlgorithmsServerToClient)
          .append(ls);
      sb.append("  compression_algorithms_client_to_server: ")
          .append(compressionAlgorithmsClientToServer)
          .append(ls);
      sb.append("  compression_algorithms_server_to_client: ")
          .append(compressionAlgorithmsServerToClient)
          .append(ls);
      sb.append("  languages_client_to_server: ").append(languagesClientToServer).append(ls);
      sb.append("  languages_server_to_client: ").append(languagesServerToClient).append(ls);
      sb.append("  first_kex_packet_follows: ").append(firstKexPacketFollows).append(ls);
      sb.append("  reserved: ").append(ByteArrays.toHexString(reserved, " ")).append(ls);

      return sb.toString();
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (!this.getClass().isInstance(obj)) {
        return false;
      }

      Ssh2KexInitHeader other = (Ssh2KexInitHeader) obj;
      return Arrays.equals(cookie, other.cookie)
          && kexAlgorithms.equals(other.kexAlgorithms)
          && serverHostKeyAlgorithms.equals(other.serverHostKeyAlgorithms)
          && encryptionAlgorithmsClientToServer.equals(other.encryptionAlgorithmsClientToServer)
          && encryptionAlgorithmsServerToClient.equals(other.encryptionAlgorithmsServerToClient)
          && macAlgorithmsClientToServer.equals(other.macAlgorithmsClientToServer)
          && macAlgorithmsServerToClient.equals(other.macAlgorithmsServerToClient)
          && compressionAlgorithmsClientToServer.equals(other.compressionAlgorithmsClientToServer)
          && compressionAlgorithmsServerToClient.equals(other.compressionAlgorithmsServerToClient)
          && languagesClientToServer.equals(other.languagesClientToServer)
          && languagesServerToClient.equals(other.languagesServerToClient)
          && firstKexPacketFollows.equals(other.firstKexPacketFollows)
          && reserved == other.reserved;
    }

    @Override
    protected int calcHashCode() {
      int result = 17;
      result = 31 * result + Arrays.hashCode(cookie);
      result = 31 * result + kexAlgorithms.hashCode();
      result = 31 * result + serverHostKeyAlgorithms.hashCode();
      result = 31 * result + encryptionAlgorithmsClientToServer.hashCode();
      result = 31 * result + encryptionAlgorithmsServerToClient.hashCode();
      result = 31 * result + macAlgorithmsClientToServer.hashCode();
      result = 31 * result + macAlgorithmsServerToClient.hashCode();
      result = 31 * result + compressionAlgorithmsClientToServer.hashCode();
      result = 31 * result + compressionAlgorithmsServerToClient.hashCode();
      result = 31 * result + languagesClientToServer.hashCode();
      result = 31 * result + languagesServerToClient.hashCode();
      result = 31 * result + firstKexPacketFollows.hashCode();
      result = 31 * result + reserved;
      return result;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy