public boolean next()

in sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java [93:196]


    public boolean next(int cmd, Buffer buffer) throws Exception {
        ServerSession session = getServerSession();
        if (log.isDebugEnabled()) {
            log.debug("next({})[{}] process command={}",
                    this, session, KeyExchange.getSimpleKexOpcodeName(cmd));
        }

        if (cmd != SshConstants.SSH_MSG_KEXDH_INIT) {
            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                    "Protocol error: expected packet SSH_MSG_KEXDH_INIT, got " + KeyExchange.getSimpleKexOpcodeName(cmd));
        }

        byte[] e = updateE(buffer);
        KeyEncapsulationMethod kem = dh.getKeyEncapsulation();
        if (kem == null) {
            dh.setF(e);
            k = normalize(dh.getK());
        } else {
            try {
                KeyEncapsulationMethod.Server kemServer = kem.getServer();

                if (dh instanceof CurveSizeIndicator) {
                    int expectedLength = kemServer.getPublicKeyLength() + ((CurveSizeIndicator) dh).getByteLength();
                    if (e.length != expectedLength) {
                        throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                                "Wrong E length (should be " + expectedLength + " bytes): " + e.length);
                    }
                } else {
                    int minLength = kemServer.getPublicKeyLength();
                    if (e.length <= minLength) {
                        throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                                "Strange E length: " + e.length + "  <= " + minLength);
                    }
                }
                dh.setF(kemServer.init(e));
                byte[] dhK = dh.getK();
                Digest keyHash = dh.getHash();
                keyHash.init();
                keyHash.update(kemServer.getSecret());
                keyHash.update(dhK);
                k = keyHash.digest();
                byte[] newF = kemServer.getEncapsulation();
                int l = newF.length;
                newF = Arrays.copyOf(newF, l + dh.getE().length);
                System.arraycopy(dh.getE(), 0, newF, l, dh.getE().length);
                setF(newF);
            } catch (IllegalArgumentException ex) {
                log.error("Key encapsulation error", ex);
                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                        "Key encapsulation error: " + ex.getMessage());
            }
        }

        KeyPair kp = Objects.requireNonNull(session.getHostKey(), "No server key pair available");
        String algo = session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);

        Signature sig = ValidateUtils.checkNotNull(
                NamedFactory.create(session.getSignatureFactories(), algo),
                "Unknown negotiated server keys: %s", algo);
        sig.initSigner(session, kp.getPrivate());

        buffer = new ByteArrayBuffer();
        buffer.putRawPublicKey(kp.getPublic());
        byte[] k_s = buffer.getCompactData();

        buffer.clear();
        buffer.putBytes(v_c);
        buffer.putBytes(v_s);
        buffer.putBytes(i_c);
        buffer.putBytes(i_s);
        buffer.putBytes(k_s);
        dh.putE(buffer, e);
        byte[] f = getF();
        dh.putF(buffer, f);
        buffer.putBytes(k);

        hash.update(buffer.array(), 0, buffer.available());
        h = hash.digest();
        sig.update(session, h);

        buffer.clear();
        buffer.putString(sig.getSshAlgorithmName(algo));
        byte[] sigBytes = sig.sign(session);
        buffer.putBytes(sigBytes);

        byte[] sigH = buffer.getCompactData();
        if (log.isTraceEnabled()) {
            log.trace("next({})[{}][K_S]:  {}", this, session, BufferUtils.toHex(k_s));
            log.trace("next({})[{}][f]:    {}", this, session, BufferUtils.toHex(f));
            log.trace("next({})[{}][sigH]: {}", this, session, BufferUtils.toHex(sigH));
        }

        // Send response
        if (log.isDebugEnabled()) {
            log.debug("next({})[{}] Send SSH_MSG_KEXDH_REPLY", this, session);
        }

        buffer = session.prepareBuffer(SshConstants.SSH_MSG_KEXDH_REPLY, BufferUtils.clear(buffer));
        buffer.putBytes(k_s);
        dh.putF(buffer, f);
        buffer.putBytes(sigH);
        session.writePacket(buffer);
        return true;
    }