package ntlm

import (
	
	
	

	
)

type Session struct {
	isClientSide bool

	user string

	negotiateFlags     uint32
	exportedSessionKey []byte
	clientSigningKey   []byte
	serverSigningKey   []byte

	clientHandle *rc4.Cipher
	serverHandle *rc4.Cipher

	infoMap map[uint16][]byte
}

func ( *Session) () string {
	return .user
}

func ( *Session) () []byte {
	return .exportedSessionKey
}

type InfoMap struct {
	NbComputerName  string
	NbDomainName    string
	DnsComputerName string
	DnsDomainName   string
	DnsTreeName     string
	// Flags           uint32
	// Timestamp       time.Time
	// SingleHost
	// TargetName string
	// ChannelBindings
}

// TODO export to somewhere
func ( *Session) () *InfoMap {
	return &InfoMap{
		NbComputerName:  utf16le.DecodeToString(.infoMap[MsvAvNbComputerName]),
		NbDomainName:    utf16le.DecodeToString(.infoMap[MsvAvNbDomainName]),
		DnsComputerName: utf16le.DecodeToString(.infoMap[MsvAvDnsComputerName]),
		DnsDomainName:   utf16le.DecodeToString(.infoMap[MsvAvDnsDomainName]),
		DnsTreeName:     utf16le.DecodeToString(.infoMap[MsvAvDnsTreeName]),
		// Flags:           le.Uint32(s.infoMap[MsvAvFlags]),
	}
}

func ( *Session) () int {
	return 16
}

func ( *Session) ( []byte,  uint32) ([]byte, uint32) {
	if .negotiateFlags&NTLMSSP_NEGOTIATE_SIGN == 0 {
		return nil, 0
	}

	if .isClientSide {
		return mac(nil, .negotiateFlags, .clientHandle, .clientSigningKey, , )
	}
	return mac(nil, .negotiateFlags, .serverHandle, .serverSigningKey, , )
}

func ( *Session) (,  []byte,  uint32) (bool, uint32) {
	if .negotiateFlags&NTLMSSP_NEGOTIATE_SIGN == 0 {
		if  == nil {
			return true, 0
		}
		return false, 0
	}

	if .isClientSide {
		,  := mac(nil, .negotiateFlags, .serverHandle, .serverSigningKey, , )
		if !bytes.Equal(, ) {
			return false, 0
		}
		return true, 
	}
	,  := mac(nil, .negotiateFlags, .clientHandle, .clientSigningKey, , )
	if !bytes.Equal(, ) {
		return false, 0
	}
	return true, 
}

func ( *Session) (,  []byte,  uint32) ([]byte, uint32) {
	,  := sliceForAppend(, len()+16)

	switch {
	case .negotiateFlags&NTLMSSP_NEGOTIATE_SEAL != 0:
		.clientHandle.XORKeyStream([16:], )

		if .isClientSide {
			_,  = mac([:0], .negotiateFlags, .clientHandle, .clientSigningKey, , )
		} else {
			_,  = mac([:0], .negotiateFlags, .serverHandle, .serverSigningKey, , )
		}
	case .negotiateFlags&NTLMSSP_NEGOTIATE_SIGN != 0:
		copy([16:], )

		if .isClientSide {
			_,  = mac([:0], .negotiateFlags, .clientHandle, .clientSigningKey, , )
		} else {
			_,  = mac([:0], .negotiateFlags, .serverHandle, .serverSigningKey, , )
		}
	}

	return , 
}

func ( *Session) (,  []byte,  uint32) ([]byte, uint32, error) {
	,  := sliceForAppend(, len()-16)

	switch {
	case .negotiateFlags&NTLMSSP_NEGOTIATE_SEAL != 0:
		.serverHandle.XORKeyStream(, [16:])

		var  []byte

		if .isClientSide {
			,  = mac(nil, .negotiateFlags, .serverHandle, .serverSigningKey, , )
		} else {
			,  = mac(nil, .negotiateFlags, .clientHandle, .clientSigningKey, , )
		}
		if !bytes.Equal([:16], ) {
			return nil, 0, errors.New("signature mismatch")
		}
	case .negotiateFlags&NTLMSSP_NEGOTIATE_SIGN != 0:
		copy(, [16:])

		var  []byte

		if .isClientSide {
			,  = mac(nil, .negotiateFlags, .serverHandle, .serverSigningKey, , )
		} else {
			,  = mac(nil, .negotiateFlags, .clientHandle, .clientSigningKey, , )
		}
		if !bytes.Equal([:16], ) {
			return nil, 0, errors.New("signature mismatch")
		}
	default:
		copy(, [16:])
		for ,  := range [:16] {
			if  != 0x0 {
				return nil, 0, errors.New("signature mismatch")
			}
		}
	}

	return , , nil
}