// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssh

import (
	
	
	
	
	
	
	
	
	
	

	
)

const (
	kexAlgoDH1SHA1                = "diffie-hellman-group1-sha1"
	kexAlgoDH14SHA1               = "diffie-hellman-group14-sha1"
	kexAlgoDH14SHA256             = "diffie-hellman-group14-sha256"
	kexAlgoDH16SHA512             = "diffie-hellman-group16-sha512"
	kexAlgoECDH256                = "ecdh-sha2-nistp256"
	kexAlgoECDH384                = "ecdh-sha2-nistp384"
	kexAlgoECDH521                = "ecdh-sha2-nistp521"
	kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org"
	kexAlgoCurve25519SHA256       = "curve25519-sha256"

	// For the following kex only the client half contains a production
	// ready implementation. The server half only consists of a minimal
	// implementation to satisfy the automated tests.
	kexAlgoDHGEXSHA1   = "diffie-hellman-group-exchange-sha1"
	kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
)

// kexResult captures the outcome of a key exchange.
type kexResult struct {
	// Session hash. See also RFC 4253, section 8.
	H []byte

	// Shared secret. See also RFC 4253, section 8.
	K []byte

	// Host key as hashed into H.
	HostKey []byte

	// Signature of H.
	Signature []byte

	// A cryptographic hash function that matches the security
	// level of the key exchange algorithm. It is used for
	// calculating H, and for deriving keys from H and K.
	Hash crypto.Hash

	// The session ID, which is the first H computed. This is used
	// to derive key material inside the transport.
	SessionID []byte
}

// handshakeMagics contains data that is always included in the
// session hash.
type handshakeMagics struct {
	clientVersion, serverVersion []byte
	clientKexInit, serverKexInit []byte
}

func ( *handshakeMagics) ( io.Writer) {
	writeString(, .clientVersion)
	writeString(, .serverVersion)
	writeString(, .clientKexInit)
	writeString(, .serverKexInit)
}

// kexAlgorithm abstracts different key exchange algorithms.
type kexAlgorithm interface {
	// Server runs server-side key agreement, signing the result
	// with a hostkey. algo is the negotiated algorithm, and may
	// be a certificate type.
	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error)

	// Client runs the client-side key agreement. Caller is
	// responsible for verifying the host key signature.
	Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
}

// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
type dhGroup struct {
	g, p, pMinus1 *big.Int
	hashFunc      crypto.Hash
}

func ( *dhGroup) (,  *big.Int) (*big.Int, error) {
	if .Cmp(bigOne) <= 0 || .Cmp(.pMinus1) >= 0 {
		return nil, errors.New("ssh: DH parameter out of bounds")
	}
	return new(big.Int).Exp(, , .p), nil
}

func ( *dhGroup) ( packetConn,  io.Reader,  *handshakeMagics) (*kexResult, error) {
	var  *big.Int
	for {
		var  error
		if ,  = rand.Int(, .pMinus1);  != nil {
			return nil, 
		}
		if .Sign() > 0 {
			break
		}
	}

	 := new(big.Int).Exp(.g, , .p)
	 := kexDHInitMsg{
		X: ,
	}
	if  := .writePacket(Marshal(&));  != nil {
		return nil, 
	}

	,  := .readPacket()
	if  != nil {
		return nil, 
	}

	var  kexDHReplyMsg
	if  = Unmarshal(, &);  != nil {
		return nil, 
	}

	,  := .diffieHellman(.Y, )
	if  != nil {
		return nil, 
	}

	 := .hashFunc.New()
	.write()
	writeString(, .HostKey)
	writeInt(, )
	writeInt(, .Y)
	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	return &kexResult{
		H:         .Sum(nil),
		K:         ,
		HostKey:   .HostKey,
		Signature: .Signature,
		Hash:      .hashFunc,
	}, nil
}

func ( *dhGroup) ( packetConn,  io.Reader,  *handshakeMagics,  AlgorithmSigner,  string) ( *kexResult,  error) {
	,  := .readPacket()
	if  != nil {
		return
	}
	var  kexDHInitMsg
	if  = Unmarshal(, &);  != nil {
		return
	}

	var  *big.Int
	for {
		if ,  = rand.Int(, .pMinus1);  != nil {
			return
		}
		if .Sign() > 0 {
			break
		}
	}

	 := new(big.Int).Exp(.g, , .p)
	,  := .diffieHellman(.X, )
	if  != nil {
		return nil, 
	}

	 := .PublicKey().Marshal()

	 := .hashFunc.New()
	.write()
	writeString(, )
	writeInt(, .X)
	writeInt(, )

	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	 := .Sum(nil)

	// H is already a hash, but the hostkey signing will apply its
	// own key-specific hash algorithm.
	,  := signAndMarshal(, , , )
	if  != nil {
		return nil, 
	}

	 := kexDHReplyMsg{
		HostKey:   ,
		Y:         ,
		Signature: ,
	}
	 = Marshal(&)

	 = .writePacket()
	return &kexResult{
		H:         ,
		K:         ,
		HostKey:   ,
		Signature: ,
		Hash:      .hashFunc,
	}, 
}

// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
// described in RFC 5656, section 4.
type ecdh struct {
	curve elliptic.Curve
}

func ( *ecdh) ( packetConn,  io.Reader,  *handshakeMagics) (*kexResult, error) {
	,  := ecdsa.GenerateKey(.curve, )
	if  != nil {
		return nil, 
	}

	 := kexECDHInitMsg{
		ClientPubKey: elliptic.Marshal(.curve, .PublicKey.X, .PublicKey.Y),
	}

	 := Marshal(&)
	if  := .writePacket();  != nil {
		return nil, 
	}

	,  := .readPacket()
	if  != nil {
		return nil, 
	}

	var  kexECDHReplyMsg
	if  = Unmarshal(, &);  != nil {
		return nil, 
	}

	, ,  := unmarshalECKey(.curve, .EphemeralPubKey)
	if  != nil {
		return nil, 
	}

	// generate shared secret
	,  := .curve.ScalarMult(, , .D.Bytes())

	 := ecHash(.curve).New()
	.write()
	writeString(, .HostKey)
	writeString(, .ClientPubKey)
	writeString(, .EphemeralPubKey)
	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	return &kexResult{
		H:         .Sum(nil),
		K:         ,
		HostKey:   .HostKey,
		Signature: .Signature,
		Hash:      ecHash(.curve),
	}, nil
}

// unmarshalECKey parses and checks an EC key.
func unmarshalECKey( elliptic.Curve,  []byte) (,  *big.Int,  error) {
	,  = elliptic.Unmarshal(, )
	if  == nil {
		return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
	}
	if !validateECPublicKey(, , ) {
		return nil, nil, errors.New("ssh: public key not on curve")
	}
	return , , nil
}

// validateECPublicKey checks that the point is a valid public key for
// the given curve. See [SEC1], 3.2.2
func validateECPublicKey( elliptic.Curve, ,  *big.Int) bool {
	if .Sign() == 0 && .Sign() == 0 {
		return false
	}

	if .Cmp(.Params().P) >= 0 {
		return false
	}

	if .Cmp(.Params().P) >= 0 {
		return false
	}

	if !.IsOnCurve(, ) {
		return false
	}

	// We don't check if N * PubKey == 0, since
	//
	// - the NIST curves have cofactor = 1, so this is implicit.
	// (We don't foresee an implementation that supports non NIST
	// curves)
	//
	// - for ephemeral keys, we don't need to worry about small
	// subgroup attacks.
	return true
}

func ( *ecdh) ( packetConn,  io.Reader,  *handshakeMagics,  AlgorithmSigner,  string) ( *kexResult,  error) {
	,  := .readPacket()
	if  != nil {
		return nil, 
	}

	var  kexECDHInitMsg
	if  = Unmarshal(, &);  != nil {
		return nil, 
	}

	, ,  := unmarshalECKey(.curve, .ClientPubKey)
	if  != nil {
		return nil, 
	}

	// We could cache this key across multiple users/multiple
	// connection attempts, but the benefit is small. OpenSSH
	// generates a new key for each incoming connection.
	,  := ecdsa.GenerateKey(.curve, )
	if  != nil {
		return nil, 
	}

	 := .PublicKey().Marshal()

	 := elliptic.Marshal(.curve, .PublicKey.X, .PublicKey.Y)

	// generate shared secret
	,  := .curve.ScalarMult(, , .D.Bytes())

	 := ecHash(.curve).New()
	.write()
	writeString(, )
	writeString(, .ClientPubKey)
	writeString(, )

	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	 := .Sum(nil)

	// H is already a hash, but the hostkey signing will apply its
	// own key-specific hash algorithm.
	,  := signAndMarshal(, , , )
	if  != nil {
		return nil, 
	}

	 := kexECDHReplyMsg{
		EphemeralPubKey: ,
		HostKey:         ,
		Signature:       ,
	}

	 := Marshal(&)
	if  := .writePacket();  != nil {
		return nil, 
	}

	return &kexResult{
		H:         ,
		K:         ,
		HostKey:   .HostKey,
		Signature: ,
		Hash:      ecHash(.curve),
	}, nil
}

// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash( elliptic.Curve) crypto.Hash {
	 := .Params().BitSize
	switch {
	case  <= 256:
		return crypto.SHA256
	case  <= 384:
		return crypto.SHA384
	}
	return crypto.SHA512
}

var kexAlgoMap = map[string]kexAlgorithm{}

func init() {
	// This is the group called diffie-hellman-group1-sha1 in
	// RFC 4253 and Oakley Group 2 in RFC 2409.
	,  := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
	kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
		g:        new(big.Int).SetInt64(2),
		p:        ,
		pMinus1:  new(big.Int).Sub(, bigOne),
		hashFunc: crypto.SHA1,
	}

	// This are the groups called diffie-hellman-group14-sha1 and
	// diffie-hellman-group14-sha256 in RFC 4253 and RFC 8268,
	// and Oakley Group 14 in RFC 3526.
	, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
	 := &dhGroup{
		g:       new(big.Int).SetInt64(2),
		p:       ,
		pMinus1: new(big.Int).Sub(, bigOne),
	}

	kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
		g: .g, p: .p, pMinus1: .pMinus1,
		hashFunc: crypto.SHA1,
	}
	kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{
		g: .g, p: .p, pMinus1: .pMinus1,
		hashFunc: crypto.SHA256,
	}

	// This is the group called diffie-hellman-group16-sha512 in RFC
	// 8268 and Oakley Group 16 in RFC 3526.
	, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", 16)

	kexAlgoMap[kexAlgoDH16SHA512] = &dhGroup{
		g:        new(big.Int).SetInt64(2),
		p:        ,
		pMinus1:  new(big.Int).Sub(, bigOne),
		hashFunc: crypto.SHA512,
	}

	kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
	kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
	kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
	kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
	kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{}
	kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
	kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
}

// curve25519sha256 implements the curve25519-sha256 (formerly known as
// curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731.
type curve25519sha256 struct{}

type curve25519KeyPair struct {
	priv [32]byte
	pub  [32]byte
}

func ( *curve25519KeyPair) ( io.Reader) error {
	if ,  := io.ReadFull(, .priv[:]);  != nil {
		return 
	}
	curve25519.ScalarBaseMult(&.pub, &.priv)
	return nil
}

// curve25519Zeros is just an array of 32 zero bytes so that we have something
// convenient to compare against in order to reject curve25519 points with the
// wrong order.
var curve25519Zeros [32]byte

func ( *curve25519sha256) ( packetConn,  io.Reader,  *handshakeMagics) (*kexResult, error) {
	var  curve25519KeyPair
	if  := .generate();  != nil {
		return nil, 
	}
	if  := .writePacket(Marshal(&kexECDHInitMsg{.pub[:]}));  != nil {
		return nil, 
	}

	,  := .readPacket()
	if  != nil {
		return nil, 
	}

	var  kexECDHReplyMsg
	if  = Unmarshal(, &);  != nil {
		return nil, 
	}
	if len(.EphemeralPubKey) != 32 {
		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
	}

	var ,  [32]byte
	copy([:], .EphemeralPubKey)
	curve25519.ScalarMult(&, &.priv, &)
	if subtle.ConstantTimeCompare([:], curve25519Zeros[:]) == 1 {
		return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
	}

	 := crypto.SHA256.New()
	.write()
	writeString(, .HostKey)
	writeString(, .pub[:])
	writeString(, .EphemeralPubKey)

	 := new(big.Int).SetBytes([:])
	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	return &kexResult{
		H:         .Sum(nil),
		K:         ,
		HostKey:   .HostKey,
		Signature: .Signature,
		Hash:      crypto.SHA256,
	}, nil
}

func ( *curve25519sha256) ( packetConn,  io.Reader,  *handshakeMagics,  AlgorithmSigner,  string) ( *kexResult,  error) {
	,  := .readPacket()
	if  != nil {
		return
	}
	var  kexECDHInitMsg
	if  = Unmarshal(, &);  != nil {
		return
	}

	if len(.ClientPubKey) != 32 {
		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
	}

	var  curve25519KeyPair
	if  := .generate();  != nil {
		return nil, 
	}

	var ,  [32]byte
	copy([:], .ClientPubKey)
	curve25519.ScalarMult(&, &.priv, &)
	if subtle.ConstantTimeCompare([:], curve25519Zeros[:]) == 1 {
		return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
	}

	 := .PublicKey().Marshal()

	 := crypto.SHA256.New()
	.write()
	writeString(, )
	writeString(, .ClientPubKey)
	writeString(, .pub[:])

	 := new(big.Int).SetBytes([:])
	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	 := .Sum(nil)

	,  := signAndMarshal(, , , )
	if  != nil {
		return nil, 
	}

	 := kexECDHReplyMsg{
		EphemeralPubKey: .pub[:],
		HostKey:         ,
		Signature:       ,
	}
	if  := .writePacket(Marshal(&));  != nil {
		return nil, 
	}
	return &kexResult{
		H:         ,
		K:         ,
		HostKey:   ,
		Signature: ,
		Hash:      crypto.SHA256,
	}, nil
}

// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
// diffie-hellman-group-exchange-sha256 key agreement protocols,
// as described in RFC 4419
type dhGEXSHA struct {
	hashFunc crypto.Hash
}

const (
	dhGroupExchangeMinimumBits   = 2048
	dhGroupExchangePreferredBits = 2048
	dhGroupExchangeMaximumBits   = 8192
)

func ( *dhGEXSHA) ( packetConn,  io.Reader,  *handshakeMagics) (*kexResult, error) {
	// Send GexRequest
	 := kexDHGexRequestMsg{
		MinBits:      dhGroupExchangeMinimumBits,
		PreferedBits: dhGroupExchangePreferredBits,
		MaxBits:      dhGroupExchangeMaximumBits,
	}
	if  := .writePacket(Marshal(&));  != nil {
		return nil, 
	}

	// Receive GexGroup
	,  := .readPacket()
	if  != nil {
		return nil, 
	}

	var  kexDHGexGroupMsg
	if  = Unmarshal(, &);  != nil {
		return nil, 
	}

	// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
	if .P.BitLen() < dhGroupExchangeMinimumBits || .P.BitLen() > dhGroupExchangeMaximumBits {
		return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", .P.BitLen())
	}

	// Check if g is safe by verifying that 1 < g < p-1
	 := new(big.Int).Sub(.P, bigOne)
	if .G.Cmp(bigOne) <= 0 || .G.Cmp() >= 0 {
		return nil, fmt.Errorf("ssh: server provided gex g is not safe")
	}

	// Send GexInit
	 := new(big.Int).Rsh(.P, 1)
	,  := rand.Int(, )
	if  != nil {
		return nil, 
	}
	 := new(big.Int).Exp(.G, , .P)
	 := kexDHGexInitMsg{
		X: ,
	}
	if  := .writePacket(Marshal(&));  != nil {
		return nil, 
	}

	// Receive GexReply
	,  = .readPacket()
	if  != nil {
		return nil, 
	}

	var  kexDHGexReplyMsg
	if  = Unmarshal(, &);  != nil {
		return nil, 
	}

	if .Y.Cmp(bigOne) <= 0 || .Y.Cmp() >= 0 {
		return nil, errors.New("ssh: DH parameter out of bounds")
	}
	 := new(big.Int).Exp(.Y, , .P)

	// Check if k is safe by verifying that k > 1 and k < p - 1
	if .Cmp(bigOne) <= 0 || .Cmp() >= 0 {
		return nil, fmt.Errorf("ssh: derived k is not safe")
	}

	 := .hashFunc.New()
	.write()
	writeString(, .HostKey)
	binary.Write(, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
	binary.Write(, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
	binary.Write(, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
	writeInt(, .P)
	writeInt(, .G)
	writeInt(, )
	writeInt(, .Y)
	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	return &kexResult{
		H:         .Sum(nil),
		K:         ,
		HostKey:   .HostKey,
		Signature: .Signature,
		Hash:      .hashFunc,
	}, nil
}

// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
//
// This is a minimal implementation to satisfy the automated tests.
func ( dhGEXSHA) ( packetConn,  io.Reader,  *handshakeMagics,  AlgorithmSigner,  string) ( *kexResult,  error) {
	// Receive GexRequest
	,  := .readPacket()
	if  != nil {
		return
	}
	var  kexDHGexRequestMsg
	if  = Unmarshal(, &);  != nil {
		return
	}

	// Send GexGroup
	// This is the group called diffie-hellman-group14-sha1 in RFC
	// 4253 and Oakley Group 14 in RFC 3526.
	,  := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
	 := big.NewInt(2)

	 := &kexDHGexGroupMsg{
		P: ,
		G: ,
	}
	if  := .writePacket(Marshal());  != nil {
		return nil, 
	}

	// Receive GexInit
	,  = .readPacket()
	if  != nil {
		return
	}
	var  kexDHGexInitMsg
	if  = Unmarshal(, &);  != nil {
		return
	}

	 := new(big.Int).Rsh(, 1)

	,  := rand.Int(, )
	if  != nil {
		return
	}
	 := new(big.Int).Exp(, , )

	 := new(big.Int).Sub(, bigOne)
	if .X.Cmp(bigOne) <= 0 || .X.Cmp() >= 0 {
		return nil, errors.New("ssh: DH parameter out of bounds")
	}
	 := new(big.Int).Exp(.X, , )

	 := .PublicKey().Marshal()

	 := .hashFunc.New()
	.write()
	writeString(, )
	binary.Write(, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
	binary.Write(, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
	binary.Write(, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
	writeInt(, )
	writeInt(, )
	writeInt(, .X)
	writeInt(, )

	 := make([]byte, intLength())
	marshalInt(, )
	.Write()

	 := .Sum(nil)

	// H is already a hash, but the hostkey signing will apply its
	// own key-specific hash algorithm.
	,  := signAndMarshal(, , , )
	if  != nil {
		return nil, 
	}

	 := kexDHGexReplyMsg{
		HostKey:   ,
		Y:         ,
		Signature: ,
	}
	 = Marshal(&)

	 = .writePacket()

	return &kexResult{
		H:         ,
		K:         ,
		HostKey:   ,
		Signature: ,
		Hash:      .hashFunc,
	}, 
}