mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	
		
			
				
	
	
		
			767 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			767 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2011 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 (
 | 
						|
	"bytes"
 | 
						|
	"encoding/binary"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"math/big"
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// These are SSH message type numbers. They are scattered around several
 | 
						|
// documents but many were taken from [SSH-PARAMETERS].
 | 
						|
const (
 | 
						|
	msgIgnore        = 2
 | 
						|
	msgUnimplemented = 3
 | 
						|
	msgDebug         = 4
 | 
						|
	msgNewKeys       = 21
 | 
						|
)
 | 
						|
 | 
						|
// SSH messages:
 | 
						|
//
 | 
						|
// These structures mirror the wire format of the corresponding SSH messages.
 | 
						|
// They are marshaled using reflection with the marshal and unmarshal functions
 | 
						|
// in this file. The only wrinkle is that a final member of type []byte with a
 | 
						|
// ssh tag of "rest" receives the remainder of a packet when unmarshaling.
 | 
						|
 | 
						|
// See RFC 4253, section 11.1.
 | 
						|
const msgDisconnect = 1
 | 
						|
 | 
						|
// disconnectMsg is the message that signals a disconnect. It is also
 | 
						|
// the error type returned from mux.Wait()
 | 
						|
type disconnectMsg struct {
 | 
						|
	Reason   uint32 `sshtype:"1"`
 | 
						|
	Message  string
 | 
						|
	Language string
 | 
						|
}
 | 
						|
 | 
						|
func (d *disconnectMsg) Error() string {
 | 
						|
	return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4253, section 7.1.
 | 
						|
const msgKexInit = 20
 | 
						|
 | 
						|
type kexInitMsg struct {
 | 
						|
	Cookie                  [16]byte `sshtype:"20"`
 | 
						|
	KexAlgos                []string
 | 
						|
	ServerHostKeyAlgos      []string
 | 
						|
	CiphersClientServer     []string
 | 
						|
	CiphersServerClient     []string
 | 
						|
	MACsClientServer        []string
 | 
						|
	MACsServerClient        []string
 | 
						|
	CompressionClientServer []string
 | 
						|
	CompressionServerClient []string
 | 
						|
	LanguagesClientServer   []string
 | 
						|
	LanguagesServerClient   []string
 | 
						|
	FirstKexFollows         bool
 | 
						|
	Reserved                uint32
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4253, section 8.
 | 
						|
 | 
						|
// Diffie-Helman
 | 
						|
const msgKexDHInit = 30
 | 
						|
 | 
						|
type kexDHInitMsg struct {
 | 
						|
	X *big.Int `sshtype:"30"`
 | 
						|
}
 | 
						|
 | 
						|
const msgKexECDHInit = 30
 | 
						|
 | 
						|
type kexECDHInitMsg struct {
 | 
						|
	ClientPubKey []byte `sshtype:"30"`
 | 
						|
}
 | 
						|
 | 
						|
const msgKexECDHReply = 31
 | 
						|
 | 
						|
type kexECDHReplyMsg struct {
 | 
						|
	HostKey         []byte `sshtype:"31"`
 | 
						|
	EphemeralPubKey []byte
 | 
						|
	Signature       []byte
 | 
						|
}
 | 
						|
 | 
						|
const msgKexDHReply = 31
 | 
						|
 | 
						|
type kexDHReplyMsg struct {
 | 
						|
	HostKey   []byte `sshtype:"31"`
 | 
						|
	Y         *big.Int
 | 
						|
	Signature []byte
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4253, section 10.
 | 
						|
const msgServiceRequest = 5
 | 
						|
 | 
						|
type serviceRequestMsg struct {
 | 
						|
	Service string `sshtype:"5"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4253, section 10.
 | 
						|
const msgServiceAccept = 6
 | 
						|
 | 
						|
type serviceAcceptMsg struct {
 | 
						|
	Service string `sshtype:"6"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4252, section 5.
 | 
						|
const msgUserAuthRequest = 50
 | 
						|
 | 
						|
type userAuthRequestMsg struct {
 | 
						|
	User    string `sshtype:"50"`
 | 
						|
	Service string
 | 
						|
	Method  string
 | 
						|
	Payload []byte `ssh:"rest"`
 | 
						|
}
 | 
						|
 | 
						|
// Used for debug printouts of packets.
 | 
						|
type userAuthSuccessMsg struct {
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4252, section 5.1
 | 
						|
const msgUserAuthFailure = 51
 | 
						|
 | 
						|
type userAuthFailureMsg struct {
 | 
						|
	Methods        []string `sshtype:"51"`
 | 
						|
	PartialSuccess bool
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4252, section 5.1
 | 
						|
const msgUserAuthSuccess = 52
 | 
						|
 | 
						|
// See RFC 4252, section 5.4
 | 
						|
const msgUserAuthBanner = 53
 | 
						|
 | 
						|
type userAuthBannerMsg struct {
 | 
						|
	Message string `sshtype:"53"`
 | 
						|
	// unused, but required to allow message parsing
 | 
						|
	Language string
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4256, section 3.2
 | 
						|
const msgUserAuthInfoRequest = 60
 | 
						|
const msgUserAuthInfoResponse = 61
 | 
						|
 | 
						|
type userAuthInfoRequestMsg struct {
 | 
						|
	User               string `sshtype:"60"`
 | 
						|
	Instruction        string
 | 
						|
	DeprecatedLanguage string
 | 
						|
	NumPrompts         uint32
 | 
						|
	Prompts            []byte `ssh:"rest"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.1.
 | 
						|
const msgChannelOpen = 90
 | 
						|
 | 
						|
type channelOpenMsg struct {
 | 
						|
	ChanType         string `sshtype:"90"`
 | 
						|
	PeersId          uint32
 | 
						|
	PeersWindow      uint32
 | 
						|
	MaxPacketSize    uint32
 | 
						|
	TypeSpecificData []byte `ssh:"rest"`
 | 
						|
}
 | 
						|
 | 
						|
const msgChannelExtendedData = 95
 | 
						|
const msgChannelData = 94
 | 
						|
 | 
						|
// Used for debug print outs of packets.
 | 
						|
type channelDataMsg struct {
 | 
						|
	PeersId uint32 `sshtype:"94"`
 | 
						|
	Length  uint32
 | 
						|
	Rest    []byte `ssh:"rest"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.1.
 | 
						|
const msgChannelOpenConfirm = 91
 | 
						|
 | 
						|
type channelOpenConfirmMsg struct {
 | 
						|
	PeersId          uint32 `sshtype:"91"`
 | 
						|
	MyId             uint32
 | 
						|
	MyWindow         uint32
 | 
						|
	MaxPacketSize    uint32
 | 
						|
	TypeSpecificData []byte `ssh:"rest"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.1.
 | 
						|
const msgChannelOpenFailure = 92
 | 
						|
 | 
						|
type channelOpenFailureMsg struct {
 | 
						|
	PeersId  uint32 `sshtype:"92"`
 | 
						|
	Reason   RejectionReason
 | 
						|
	Message  string
 | 
						|
	Language string
 | 
						|
}
 | 
						|
 | 
						|
const msgChannelRequest = 98
 | 
						|
 | 
						|
type channelRequestMsg struct {
 | 
						|
	PeersId             uint32 `sshtype:"98"`
 | 
						|
	Request             string
 | 
						|
	WantReply           bool
 | 
						|
	RequestSpecificData []byte `ssh:"rest"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.4.
 | 
						|
const msgChannelSuccess = 99
 | 
						|
 | 
						|
type channelRequestSuccessMsg struct {
 | 
						|
	PeersId uint32 `sshtype:"99"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.4.
 | 
						|
const msgChannelFailure = 100
 | 
						|
 | 
						|
type channelRequestFailureMsg struct {
 | 
						|
	PeersId uint32 `sshtype:"100"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.3
 | 
						|
const msgChannelClose = 97
 | 
						|
 | 
						|
type channelCloseMsg struct {
 | 
						|
	PeersId uint32 `sshtype:"97"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.3
 | 
						|
const msgChannelEOF = 96
 | 
						|
 | 
						|
type channelEOFMsg struct {
 | 
						|
	PeersId uint32 `sshtype:"96"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 4
 | 
						|
const msgGlobalRequest = 80
 | 
						|
 | 
						|
type globalRequestMsg struct {
 | 
						|
	Type      string `sshtype:"80"`
 | 
						|
	WantReply bool
 | 
						|
	Data      []byte `ssh:"rest"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 4
 | 
						|
const msgRequestSuccess = 81
 | 
						|
 | 
						|
type globalRequestSuccessMsg struct {
 | 
						|
	Data []byte `ssh:"rest" sshtype:"81"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 4
 | 
						|
const msgRequestFailure = 82
 | 
						|
 | 
						|
type globalRequestFailureMsg struct {
 | 
						|
	Data []byte `ssh:"rest" sshtype:"82"`
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4254, section 5.2
 | 
						|
const msgChannelWindowAdjust = 93
 | 
						|
 | 
						|
type windowAdjustMsg struct {
 | 
						|
	PeersId         uint32 `sshtype:"93"`
 | 
						|
	AdditionalBytes uint32
 | 
						|
}
 | 
						|
 | 
						|
// See RFC 4252, section 7
 | 
						|
const msgUserAuthPubKeyOk = 60
 | 
						|
 | 
						|
type userAuthPubKeyOkMsg struct {
 | 
						|
	Algo   string `sshtype:"60"`
 | 
						|
	PubKey []byte
 | 
						|
}
 | 
						|
 | 
						|
// typeTags returns the possible type bytes for the given reflect.Type, which
 | 
						|
// should be a struct. The possible values are separated by a '|' character.
 | 
						|
func typeTags(structType reflect.Type) (tags []byte) {
 | 
						|
	tagStr := structType.Field(0).Tag.Get("sshtype")
 | 
						|
 | 
						|
	for _, tag := range strings.Split(tagStr, "|") {
 | 
						|
		i, err := strconv.Atoi(tag)
 | 
						|
		if err == nil {
 | 
						|
			tags = append(tags, byte(i))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return tags
 | 
						|
}
 | 
						|
 | 
						|
func fieldError(t reflect.Type, field int, problem string) error {
 | 
						|
	if problem != "" {
 | 
						|
		problem = ": " + problem
 | 
						|
	}
 | 
						|
	return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
 | 
						|
}
 | 
						|
 | 
						|
var errShortRead = errors.New("ssh: short read")
 | 
						|
 | 
						|
// Unmarshal parses data in SSH wire format into a structure. The out
 | 
						|
// argument should be a pointer to struct. If the first member of the
 | 
						|
// struct has the "sshtype" tag set to a '|'-separated set of numbers
 | 
						|
// in decimal, the packet must start with one of those numbers. In
 | 
						|
// case of error, Unmarshal returns a ParseError or
 | 
						|
// UnexpectedMessageError.
 | 
						|
func Unmarshal(data []byte, out interface{}) error {
 | 
						|
	v := reflect.ValueOf(out).Elem()
 | 
						|
	structType := v.Type()
 | 
						|
	expectedTypes := typeTags(structType)
 | 
						|
 | 
						|
	var expectedType byte
 | 
						|
	if len(expectedTypes) > 0 {
 | 
						|
		expectedType = expectedTypes[0]
 | 
						|
	}
 | 
						|
 | 
						|
	if len(data) == 0 {
 | 
						|
		return parseError(expectedType)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(expectedTypes) > 0 {
 | 
						|
		goodType := false
 | 
						|
		for _, e := range expectedTypes {
 | 
						|
			if e > 0 && data[0] == e {
 | 
						|
				goodType = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if !goodType {
 | 
						|
			return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
 | 
						|
		}
 | 
						|
		data = data[1:]
 | 
						|
	}
 | 
						|
 | 
						|
	var ok bool
 | 
						|
	for i := 0; i < v.NumField(); i++ {
 | 
						|
		field := v.Field(i)
 | 
						|
		t := field.Type()
 | 
						|
		switch t.Kind() {
 | 
						|
		case reflect.Bool:
 | 
						|
			if len(data) < 1 {
 | 
						|
				return errShortRead
 | 
						|
			}
 | 
						|
			field.SetBool(data[0] != 0)
 | 
						|
			data = data[1:]
 | 
						|
		case reflect.Array:
 | 
						|
			if t.Elem().Kind() != reflect.Uint8 {
 | 
						|
				return fieldError(structType, i, "array of unsupported type")
 | 
						|
			}
 | 
						|
			if len(data) < t.Len() {
 | 
						|
				return errShortRead
 | 
						|
			}
 | 
						|
			for j, n := 0, t.Len(); j < n; j++ {
 | 
						|
				field.Index(j).Set(reflect.ValueOf(data[j]))
 | 
						|
			}
 | 
						|
			data = data[t.Len():]
 | 
						|
		case reflect.Uint64:
 | 
						|
			var u64 uint64
 | 
						|
			if u64, data, ok = parseUint64(data); !ok {
 | 
						|
				return errShortRead
 | 
						|
			}
 | 
						|
			field.SetUint(u64)
 | 
						|
		case reflect.Uint32:
 | 
						|
			var u32 uint32
 | 
						|
			if u32, data, ok = parseUint32(data); !ok {
 | 
						|
				return errShortRead
 | 
						|
			}
 | 
						|
			field.SetUint(uint64(u32))
 | 
						|
		case reflect.Uint8:
 | 
						|
			if len(data) < 1 {
 | 
						|
				return errShortRead
 | 
						|
			}
 | 
						|
			field.SetUint(uint64(data[0]))
 | 
						|
			data = data[1:]
 | 
						|
		case reflect.String:
 | 
						|
			var s []byte
 | 
						|
			if s, data, ok = parseString(data); !ok {
 | 
						|
				return fieldError(structType, i, "")
 | 
						|
			}
 | 
						|
			field.SetString(string(s))
 | 
						|
		case reflect.Slice:
 | 
						|
			switch t.Elem().Kind() {
 | 
						|
			case reflect.Uint8:
 | 
						|
				if structType.Field(i).Tag.Get("ssh") == "rest" {
 | 
						|
					field.Set(reflect.ValueOf(data))
 | 
						|
					data = nil
 | 
						|
				} else {
 | 
						|
					var s []byte
 | 
						|
					if s, data, ok = parseString(data); !ok {
 | 
						|
						return errShortRead
 | 
						|
					}
 | 
						|
					field.Set(reflect.ValueOf(s))
 | 
						|
				}
 | 
						|
			case reflect.String:
 | 
						|
				var nl []string
 | 
						|
				if nl, data, ok = parseNameList(data); !ok {
 | 
						|
					return errShortRead
 | 
						|
				}
 | 
						|
				field.Set(reflect.ValueOf(nl))
 | 
						|
			default:
 | 
						|
				return fieldError(structType, i, "slice of unsupported type")
 | 
						|
			}
 | 
						|
		case reflect.Ptr:
 | 
						|
			if t == bigIntType {
 | 
						|
				var n *big.Int
 | 
						|
				if n, data, ok = parseInt(data); !ok {
 | 
						|
					return errShortRead
 | 
						|
				}
 | 
						|
				field.Set(reflect.ValueOf(n))
 | 
						|
			} else {
 | 
						|
				return fieldError(structType, i, "pointer to unsupported type")
 | 
						|
			}
 | 
						|
		default:
 | 
						|
			return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if len(data) != 0 {
 | 
						|
		return parseError(expectedType)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Marshal serializes the message in msg to SSH wire format.  The msg
 | 
						|
// argument should be a struct or pointer to struct. If the first
 | 
						|
// member has the "sshtype" tag set to a number in decimal, that
 | 
						|
// number is prepended to the result. If the last of member has the
 | 
						|
// "ssh" tag set to "rest", its contents are appended to the output.
 | 
						|
func Marshal(msg interface{}) []byte {
 | 
						|
	out := make([]byte, 0, 64)
 | 
						|
	return marshalStruct(out, msg)
 | 
						|
}
 | 
						|
 | 
						|
func marshalStruct(out []byte, msg interface{}) []byte {
 | 
						|
	v := reflect.Indirect(reflect.ValueOf(msg))
 | 
						|
	msgTypes := typeTags(v.Type())
 | 
						|
	if len(msgTypes) > 0 {
 | 
						|
		out = append(out, msgTypes[0])
 | 
						|
	}
 | 
						|
 | 
						|
	for i, n := 0, v.NumField(); i < n; i++ {
 | 
						|
		field := v.Field(i)
 | 
						|
		switch t := field.Type(); t.Kind() {
 | 
						|
		case reflect.Bool:
 | 
						|
			var v uint8
 | 
						|
			if field.Bool() {
 | 
						|
				v = 1
 | 
						|
			}
 | 
						|
			out = append(out, v)
 | 
						|
		case reflect.Array:
 | 
						|
			if t.Elem().Kind() != reflect.Uint8 {
 | 
						|
				panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface()))
 | 
						|
			}
 | 
						|
			for j, l := 0, t.Len(); j < l; j++ {
 | 
						|
				out = append(out, uint8(field.Index(j).Uint()))
 | 
						|
			}
 | 
						|
		case reflect.Uint32:
 | 
						|
			out = appendU32(out, uint32(field.Uint()))
 | 
						|
		case reflect.Uint64:
 | 
						|
			out = appendU64(out, uint64(field.Uint()))
 | 
						|
		case reflect.Uint8:
 | 
						|
			out = append(out, uint8(field.Uint()))
 | 
						|
		case reflect.String:
 | 
						|
			s := field.String()
 | 
						|
			out = appendInt(out, len(s))
 | 
						|
			out = append(out, s...)
 | 
						|
		case reflect.Slice:
 | 
						|
			switch t.Elem().Kind() {
 | 
						|
			case reflect.Uint8:
 | 
						|
				if v.Type().Field(i).Tag.Get("ssh") != "rest" {
 | 
						|
					out = appendInt(out, field.Len())
 | 
						|
				}
 | 
						|
				out = append(out, field.Bytes()...)
 | 
						|
			case reflect.String:
 | 
						|
				offset := len(out)
 | 
						|
				out = appendU32(out, 0)
 | 
						|
				if n := field.Len(); n > 0 {
 | 
						|
					for j := 0; j < n; j++ {
 | 
						|
						f := field.Index(j)
 | 
						|
						if j != 0 {
 | 
						|
							out = append(out, ',')
 | 
						|
						}
 | 
						|
						out = append(out, f.String()...)
 | 
						|
					}
 | 
						|
					// overwrite length value
 | 
						|
					binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4))
 | 
						|
				}
 | 
						|
			default:
 | 
						|
				panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface()))
 | 
						|
			}
 | 
						|
		case reflect.Ptr:
 | 
						|
			if t == bigIntType {
 | 
						|
				var n *big.Int
 | 
						|
				nValue := reflect.ValueOf(&n)
 | 
						|
				nValue.Elem().Set(field)
 | 
						|
				needed := intLength(n)
 | 
						|
				oldLength := len(out)
 | 
						|
 | 
						|
				if cap(out)-len(out) < needed {
 | 
						|
					newOut := make([]byte, len(out), 2*(len(out)+needed))
 | 
						|
					copy(newOut, out)
 | 
						|
					out = newOut
 | 
						|
				}
 | 
						|
				out = out[:oldLength+needed]
 | 
						|
				marshalInt(out[oldLength:], n)
 | 
						|
			} else {
 | 
						|
				panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface()))
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return out
 | 
						|
}
 | 
						|
 | 
						|
var bigOne = big.NewInt(1)
 | 
						|
 | 
						|
func parseString(in []byte) (out, rest []byte, ok bool) {
 | 
						|
	if len(in) < 4 {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	length := binary.BigEndian.Uint32(in)
 | 
						|
	in = in[4:]
 | 
						|
	if uint32(len(in)) < length {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	out = in[:length]
 | 
						|
	rest = in[length:]
 | 
						|
	ok = true
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	comma         = []byte{','}
 | 
						|
	emptyNameList = []string{}
 | 
						|
)
 | 
						|
 | 
						|
func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
 | 
						|
	contents, rest, ok := parseString(in)
 | 
						|
	if !ok {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if len(contents) == 0 {
 | 
						|
		out = emptyNameList
 | 
						|
		return
 | 
						|
	}
 | 
						|
	parts := bytes.Split(contents, comma)
 | 
						|
	out = make([]string, len(parts))
 | 
						|
	for i, part := range parts {
 | 
						|
		out[i] = string(part)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
 | 
						|
	contents, rest, ok := parseString(in)
 | 
						|
	if !ok {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	out = new(big.Int)
 | 
						|
 | 
						|
	if len(contents) > 0 && contents[0]&0x80 == 0x80 {
 | 
						|
		// This is a negative number
 | 
						|
		notBytes := make([]byte, len(contents))
 | 
						|
		for i := range notBytes {
 | 
						|
			notBytes[i] = ^contents[i]
 | 
						|
		}
 | 
						|
		out.SetBytes(notBytes)
 | 
						|
		out.Add(out, bigOne)
 | 
						|
		out.Neg(out)
 | 
						|
	} else {
 | 
						|
		// Positive number
 | 
						|
		out.SetBytes(contents)
 | 
						|
	}
 | 
						|
	ok = true
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func parseUint32(in []byte) (uint32, []byte, bool) {
 | 
						|
	if len(in) < 4 {
 | 
						|
		return 0, nil, false
 | 
						|
	}
 | 
						|
	return binary.BigEndian.Uint32(in), in[4:], true
 | 
						|
}
 | 
						|
 | 
						|
func parseUint64(in []byte) (uint64, []byte, bool) {
 | 
						|
	if len(in) < 8 {
 | 
						|
		return 0, nil, false
 | 
						|
	}
 | 
						|
	return binary.BigEndian.Uint64(in), in[8:], true
 | 
						|
}
 | 
						|
 | 
						|
func intLength(n *big.Int) int {
 | 
						|
	length := 4 /* length bytes */
 | 
						|
	if n.Sign() < 0 {
 | 
						|
		nMinus1 := new(big.Int).Neg(n)
 | 
						|
		nMinus1.Sub(nMinus1, bigOne)
 | 
						|
		bitLen := nMinus1.BitLen()
 | 
						|
		if bitLen%8 == 0 {
 | 
						|
			// The number will need 0xff padding
 | 
						|
			length++
 | 
						|
		}
 | 
						|
		length += (bitLen + 7) / 8
 | 
						|
	} else if n.Sign() == 0 {
 | 
						|
		// A zero is the zero length string
 | 
						|
	} else {
 | 
						|
		bitLen := n.BitLen()
 | 
						|
		if bitLen%8 == 0 {
 | 
						|
			// The number will need 0x00 padding
 | 
						|
			length++
 | 
						|
		}
 | 
						|
		length += (bitLen + 7) / 8
 | 
						|
	}
 | 
						|
 | 
						|
	return length
 | 
						|
}
 | 
						|
 | 
						|
func marshalUint32(to []byte, n uint32) []byte {
 | 
						|
	binary.BigEndian.PutUint32(to, n)
 | 
						|
	return to[4:]
 | 
						|
}
 | 
						|
 | 
						|
func marshalUint64(to []byte, n uint64) []byte {
 | 
						|
	binary.BigEndian.PutUint64(to, n)
 | 
						|
	return to[8:]
 | 
						|
}
 | 
						|
 | 
						|
func marshalInt(to []byte, n *big.Int) []byte {
 | 
						|
	lengthBytes := to
 | 
						|
	to = to[4:]
 | 
						|
	length := 0
 | 
						|
 | 
						|
	if n.Sign() < 0 {
 | 
						|
		// A negative number has to be converted to two's-complement
 | 
						|
		// form. So we'll subtract 1 and invert. If the
 | 
						|
		// most-significant-bit isn't set then we'll need to pad the
 | 
						|
		// beginning with 0xff in order to keep the number negative.
 | 
						|
		nMinus1 := new(big.Int).Neg(n)
 | 
						|
		nMinus1.Sub(nMinus1, bigOne)
 | 
						|
		bytes := nMinus1.Bytes()
 | 
						|
		for i := range bytes {
 | 
						|
			bytes[i] ^= 0xff
 | 
						|
		}
 | 
						|
		if len(bytes) == 0 || bytes[0]&0x80 == 0 {
 | 
						|
			to[0] = 0xff
 | 
						|
			to = to[1:]
 | 
						|
			length++
 | 
						|
		}
 | 
						|
		nBytes := copy(to, bytes)
 | 
						|
		to = to[nBytes:]
 | 
						|
		length += nBytes
 | 
						|
	} else if n.Sign() == 0 {
 | 
						|
		// A zero is the zero length string
 | 
						|
	} else {
 | 
						|
		bytes := n.Bytes()
 | 
						|
		if len(bytes) > 0 && bytes[0]&0x80 != 0 {
 | 
						|
			// We'll have to pad this with a 0x00 in order to
 | 
						|
			// stop it looking like a negative number.
 | 
						|
			to[0] = 0
 | 
						|
			to = to[1:]
 | 
						|
			length++
 | 
						|
		}
 | 
						|
		nBytes := copy(to, bytes)
 | 
						|
		to = to[nBytes:]
 | 
						|
		length += nBytes
 | 
						|
	}
 | 
						|
 | 
						|
	lengthBytes[0] = byte(length >> 24)
 | 
						|
	lengthBytes[1] = byte(length >> 16)
 | 
						|
	lengthBytes[2] = byte(length >> 8)
 | 
						|
	lengthBytes[3] = byte(length)
 | 
						|
	return to
 | 
						|
}
 | 
						|
 | 
						|
func writeInt(w io.Writer, n *big.Int) {
 | 
						|
	length := intLength(n)
 | 
						|
	buf := make([]byte, length)
 | 
						|
	marshalInt(buf, n)
 | 
						|
	w.Write(buf)
 | 
						|
}
 | 
						|
 | 
						|
func writeString(w io.Writer, s []byte) {
 | 
						|
	var lengthBytes [4]byte
 | 
						|
	lengthBytes[0] = byte(len(s) >> 24)
 | 
						|
	lengthBytes[1] = byte(len(s) >> 16)
 | 
						|
	lengthBytes[2] = byte(len(s) >> 8)
 | 
						|
	lengthBytes[3] = byte(len(s))
 | 
						|
	w.Write(lengthBytes[:])
 | 
						|
	w.Write(s)
 | 
						|
}
 | 
						|
 | 
						|
func stringLength(n int) int {
 | 
						|
	return 4 + n
 | 
						|
}
 | 
						|
 | 
						|
func marshalString(to []byte, s []byte) []byte {
 | 
						|
	to[0] = byte(len(s) >> 24)
 | 
						|
	to[1] = byte(len(s) >> 16)
 | 
						|
	to[2] = byte(len(s) >> 8)
 | 
						|
	to[3] = byte(len(s))
 | 
						|
	to = to[4:]
 | 
						|
	copy(to, s)
 | 
						|
	return to[len(s):]
 | 
						|
}
 | 
						|
 | 
						|
var bigIntType = reflect.TypeOf((*big.Int)(nil))
 | 
						|
 | 
						|
// Decode a packet into its corresponding message.
 | 
						|
func decode(packet []byte) (interface{}, error) {
 | 
						|
	var msg interface{}
 | 
						|
	switch packet[0] {
 | 
						|
	case msgDisconnect:
 | 
						|
		msg = new(disconnectMsg)
 | 
						|
	case msgServiceRequest:
 | 
						|
		msg = new(serviceRequestMsg)
 | 
						|
	case msgServiceAccept:
 | 
						|
		msg = new(serviceAcceptMsg)
 | 
						|
	case msgKexInit:
 | 
						|
		msg = new(kexInitMsg)
 | 
						|
	case msgKexDHInit:
 | 
						|
		msg = new(kexDHInitMsg)
 | 
						|
	case msgKexDHReply:
 | 
						|
		msg = new(kexDHReplyMsg)
 | 
						|
	case msgUserAuthRequest:
 | 
						|
		msg = new(userAuthRequestMsg)
 | 
						|
	case msgUserAuthSuccess:
 | 
						|
		return new(userAuthSuccessMsg), nil
 | 
						|
	case msgUserAuthFailure:
 | 
						|
		msg = new(userAuthFailureMsg)
 | 
						|
	case msgUserAuthPubKeyOk:
 | 
						|
		msg = new(userAuthPubKeyOkMsg)
 | 
						|
	case msgGlobalRequest:
 | 
						|
		msg = new(globalRequestMsg)
 | 
						|
	case msgRequestSuccess:
 | 
						|
		msg = new(globalRequestSuccessMsg)
 | 
						|
	case msgRequestFailure:
 | 
						|
		msg = new(globalRequestFailureMsg)
 | 
						|
	case msgChannelOpen:
 | 
						|
		msg = new(channelOpenMsg)
 | 
						|
	case msgChannelData:
 | 
						|
		msg = new(channelDataMsg)
 | 
						|
	case msgChannelOpenConfirm:
 | 
						|
		msg = new(channelOpenConfirmMsg)
 | 
						|
	case msgChannelOpenFailure:
 | 
						|
		msg = new(channelOpenFailureMsg)
 | 
						|
	case msgChannelWindowAdjust:
 | 
						|
		msg = new(windowAdjustMsg)
 | 
						|
	case msgChannelEOF:
 | 
						|
		msg = new(channelEOFMsg)
 | 
						|
	case msgChannelClose:
 | 
						|
		msg = new(channelCloseMsg)
 | 
						|
	case msgChannelRequest:
 | 
						|
		msg = new(channelRequestMsg)
 | 
						|
	case msgChannelSuccess:
 | 
						|
		msg = new(channelRequestSuccessMsg)
 | 
						|
	case msgChannelFailure:
 | 
						|
		msg = new(channelRequestFailureMsg)
 | 
						|
	default:
 | 
						|
		return nil, unexpectedMessageError(0, packet[0])
 | 
						|
	}
 | 
						|
	if err := Unmarshal(packet, msg); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return msg, nil
 | 
						|
}
 |