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"
	kexAlgoECDH256          = "ecdh-sha2-nistp256"
	kexAlgoECDH384          = "ecdh-sha2-nistp384"
	kexAlgoECDH521          = "ecdh-sha2-nistp521"
	kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org"
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.
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.
Signature of H.
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.
The session ID, which is the first H computed. This is used to derive key material inside the transport.
handshakeMagics contains data that is always included in the session hash.
kexAlgorithm abstracts different key exchange algorithms.
Server runs server-side key agreement, signing the result with a hostkey.
	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*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
}

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) {
	 := crypto.SHA1

	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, 
	}

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

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

func ( *dhGroup) ( packetConn,  io.Reader,  *handshakeMagics,  Signer) ( *kexResult,  error) {
	 := crypto.SHA1
	,  := .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()

	 := .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:      crypto.SHA1,
	}, 
}
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 ( 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 ( 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,  Signer) ( *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
}

var kexAlgoMap = map[string]kexAlgorithm{}

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),
	}
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)

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

	kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
	kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
	kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
	kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
	kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
	kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
}
curve25519sha256 implements the curve25519-sha256@libssh.org key agreement protocol, as described in https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
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,  Signer) ( *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 {
	g, p     *big.Int
	hashFunc crypto.Hash
}

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

func ( *dhGEXSHA) (,  *big.Int) (*big.Int, error) {
	if .Sign() <= 0 || .Cmp(.p) >= 0 {
		return nil, fmt.Errorf("ssh: DH parameter out of bounds")
	}
	return new(big.Int).Exp(, , .p), nil
}

Send GexRequest
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())
	}

	.p = .P
	.g = .G
Check if g is safe by verifing that g > 1 and g < p - 1
	 := big.NewInt(1)
	var  = &big.Int{}
	.Sub(.p, )
	if .g.Cmp() != 1 && .g.Cmp() != -1 {
		return nil, fmt.Errorf("ssh: server provided gex g is not safe")
	}
Send GexInit
	var  = &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, 
	}

	,  := .diffieHellman(.Y, )
	if  != nil {
		return nil, 
	}
Check if k is safe by verifing that k > 1 and k < p - 1
	if .Cmp() != 1 && .Cmp() != -1 {
		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.
Receive GexRequest
	,  := .readPacket()
	if  != nil {
		return
	}
	var  kexDHGexRequestMsg
	if  = Unmarshal(, &);  != nil {
		return
	}
smoosh the user's preferred size into our own limits
fix min/max if they're inconsistent. technically, we could just pout and hang up, but there's no harm in giving them the benefit of the doubt and just picking a bitsize for them.
	if .MinBits > .PreferedBits {
		.MinBits = .PreferedBits
	}
	if .MaxBits < .PreferedBits {
		.MaxBits = .PreferedBits
	}
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)
	.p = 
	.g = big.NewInt(2)

	 := kexDHGexGroupMsg{
		P: .p,
		G: .g,
	}
	if  := .writePacket(Marshal(&));  != nil {
		return nil, 
	}
Receive GexInit
	,  = .readPacket()
	if  != nil {
		return
	}
	var  kexDHGexInitMsg
	if  = Unmarshal(, &);  != nil {
		return
	}

	var  = &big.Int{}
	.Rsh(.p, 1)

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

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

	 := .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(, .p)
	writeInt(, .g)
	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,
	},