@Override
  public boolean next(Message msg, SSHPacket packet)
      throws GeneralSecurityException, TransportException {
    if (msg != Message.KEXDH_31)
      throw new TransportException(
          DisconnectReason.KEY_EXCHANGE_FAILED, "Unexpected packet: " + msg);

    log.debug("Received SSH_MSG_KEXDH_REPLY");
    final byte[] K_S;
    final BigInteger f;
    final byte[] sig; // signature sent by server
    try {
      K_S = packet.readBytes();
      f = packet.readMPInt();
      sig = packet.readBytes();
      hostKey = new Buffer.PlainBuffer(K_S).readPublicKey();
    } catch (Buffer.BufferException be) {
      throw new TransportException(be);
    }

    dh.computeK(f);

    final Buffer.PlainBuffer buf =
        new Buffer.PlainBuffer()
            .putString(V_C)
            .putString(V_S)
            .putString(I_C)
            .putString(I_S)
            .putString(K_S)
            .putMPInt(dh.getE())
            .putMPInt(f)
            .putMPInt(dh.getK());
    sha1.update(buf.array(), buf.rpos(), buf.available());
    H = sha1.digest();

    Signature signature =
        Factory.Named.Util.create(
            trans.getConfig().getSignatureFactories(), KeyType.fromKey(hostKey).toString());
    signature.init(hostKey, null);
    signature.update(H, 0, H.length);
    if (!signature.verify(sig))
      throw new TransportException(
          DisconnectReason.KEY_EXCHANGE_FAILED, "KeyExchange signature verification failed");
    return true;
  }
  @Override
  public void init(Transport trans, String V_S, String V_C, byte[] I_S, byte[] I_C)
      throws GeneralSecurityException, TransportException {
    this.trans = trans;
    this.V_S = V_S;
    this.V_C = V_C;
    this.I_S = Arrays.copyOf(I_S, I_S.length);
    this.I_C = Arrays.copyOf(I_C, I_C.length);
    sha1.init();
    initDH(dh);

    log.debug("Sending SSH_MSG_KEXDH_INIT");
    trans.write(new SSHPacket(Message.KEXDH_INIT).putMPInt(dh.getE()));
  }