github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/upstreamproxy/go-ntlm/ntlm/challenge_responses.go (about)

     1  //Copyright 2013 Thomson Reuters Global Resources. BSD License please see License file for more information
     2  
     3  package ntlm
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/hex"
     8  	"errors"
     9  	"fmt"
    10  )
    11  
    12  // NTLMv1
    13  // ******
    14  type NtlmV1Response struct {
    15  	// 24 byte array
    16  	Response []byte
    17  }
    18  
    19  func (n *NtlmV1Response) String() string {
    20  	return fmt.Sprintf("NtlmV1Response: %s", hex.EncodeToString(n.Response))
    21  }
    22  
    23  func ReadNtlmV1Response(bytes []byte) (*NtlmV1Response, error) {
    24  
    25  	// [Psiphon]
    26  	// Don't panic on malformed remote input.
    27  	if len(bytes) < 24 {
    28  		return nil, errors.New("invalid NTLM v1 response")
    29  	}
    30  
    31  	r := new(NtlmV1Response)
    32  	r.Response = bytes[0:24]
    33  	return r, nil
    34  }
    35  
    36  // *** NTLMv2
    37  // The NTLMv2_CLIENT_CHALLENGE structure defines the client challenge in the AUTHENTICATE_MESSAGE.
    38  // This structure is used only when NTLM v2 authentication is configured.
    39  type NtlmV2ClientChallenge struct {
    40  	// An 8-bit unsigned char that contains the current version of the challenge response type.
    41  	// This field MUST be 0x01.
    42  	RespType byte
    43  	// An 8-bit unsigned char that contains the maximum supported version of the challenge response type.
    44  	// This field MUST be 0x01.
    45  	HiRespType byte
    46  	// A 16-bit unsigned integer that SHOULD be 0x0000 and MUST be ignored on receipt.
    47  	Reserved1 uint16
    48  	// A 32-bit unsigned integer that SHOULD be 0x00000000 and MUST be ignored on receipt.
    49  	Reserved2 uint32
    50  	// A 64-bit unsigned integer that contains the current system time, represented as the number of 100 nanosecond
    51  	// ticks elapsed since midnight of January 1, 1601 (UTC).
    52  	TimeStamp []byte
    53  	// An 8-byte array of unsigned char that contains the client's ClientChallenge (section 3.1.5.1.2).
    54  	ChallengeFromClient []byte
    55  	// A 32-bit unsigned integer that SHOULD be 0x00000000 and MUST be ignored on receipt.
    56  	Reserved3 uint32
    57  	AvPairs   *AvPairs
    58  }
    59  
    60  func (n *NtlmV2ClientChallenge) String() string {
    61  	var buffer bytes.Buffer
    62  
    63  	buffer.WriteString("NTLM v2 ClientChallenge\n")
    64  	buffer.WriteString(fmt.Sprintf("Timestamp: %s\n", hex.EncodeToString(n.TimeStamp)))
    65  	buffer.WriteString(fmt.Sprintf("ChallengeFromClient: %s\n", hex.EncodeToString(n.ChallengeFromClient)))
    66  	buffer.WriteString("AvPairs\n")
    67  	buffer.WriteString(n.AvPairs.String())
    68  
    69  	return buffer.String()
    70  }
    71  
    72  // The NTLMv2_RESPONSE structure defines the NTLMv2 authentication NtChallengeResponse in the AUTHENTICATE_MESSAGE.
    73  // This response is used only when NTLMv2 authentication is configured.
    74  type NtlmV2Response struct {
    75  	// A 16-byte array of unsigned char that contains the client's NT challenge- response as defined in section 3.3.2.
    76  	// Response corresponds to the NTProofStr variable from section 3.3.2.
    77  	Response []byte
    78  	// A variable-length byte array that contains the ClientChallenge as defined in section 3.3.2.
    79  	// ChallengeFromClient corresponds to the temp variable from section 3.3.2.
    80  	NtlmV2ClientChallenge *NtlmV2ClientChallenge
    81  }
    82  
    83  func (n *NtlmV2Response) String() string {
    84  	var buffer bytes.Buffer
    85  
    86  	buffer.WriteString("NTLM v2 Response\n")
    87  	buffer.WriteString(fmt.Sprintf("Response: %s\n", hex.EncodeToString(n.Response)))
    88  	buffer.WriteString(n.NtlmV2ClientChallenge.String())
    89  
    90  	return buffer.String()
    91  }
    92  
    93  func ReadNtlmV2Response(bytes []byte) (*NtlmV2Response, error) {
    94  
    95  	// [Psiphon]
    96  	// Don't panic on malformed remote input.
    97  	if len(bytes) < 45 {
    98  		return nil, errors.New("invalid NTLM v2 response")
    99  	}
   100  
   101  	r := new(NtlmV2Response)
   102  	r.Response = bytes[0:16]
   103  	r.NtlmV2ClientChallenge = new(NtlmV2ClientChallenge)
   104  	c := r.NtlmV2ClientChallenge
   105  	c.RespType = bytes[16]
   106  	c.HiRespType = bytes[17]
   107  
   108  	if c.RespType != 1 || c.HiRespType != 1 {
   109  		return nil, errors.New("Does not contain a valid NTLM v2 client challenge - could be NTLMv1.")
   110  	}
   111  
   112  	// Ignoring - 2 bytes reserved
   113  	// c.Reserved1
   114  	// Ignoring - 4 bytes reserved
   115  	// c.Reserved2
   116  	c.TimeStamp = bytes[24:32]
   117  	c.ChallengeFromClient = bytes[32:40]
   118  	// Ignoring - 4 bytes reserved
   119  	// c.Reserved3
   120  	var err error
   121  	c.AvPairs, err = ReadAvPairs(bytes[44:])
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	return r, nil
   126  }
   127  
   128  // LMv1
   129  // ****
   130  type LmV1Response struct {
   131  	// 24 bytes
   132  	Response []byte
   133  }
   134  
   135  func ReadLmV1Response(bytes []byte) (*LmV1Response, error) {
   136  
   137  	// [Psiphon]
   138  	// Don't panic on malformed remote input.
   139  	if len(bytes) < 24 {
   140  		return nil, errors.New("invalid LM v1 response")
   141  	}
   142  
   143  	r := new(LmV1Response)
   144  	r.Response = bytes[0:24]
   145  	return r, nil
   146  }
   147  
   148  func (l *LmV1Response) String() string {
   149  	return fmt.Sprintf("LmV1Response: %s", hex.EncodeToString(l.Response))
   150  }
   151  
   152  // *** LMv2
   153  type LmV2Response struct {
   154  	// A 16-byte array of unsigned char that contains the client's LM challenge-response.
   155  	// This is the portion of the LmChallengeResponse field to which the HMAC_MD5 algorithm
   156  	/// has been applied, as defined in section 3.3.2. Specifically, Response corresponds
   157  	// to the result of applying the HMAC_MD5 algorithm, using the key ResponseKeyLM, to a
   158  	// message consisting of the concatenation of the ResponseKeyLM, ServerChallenge and ClientChallenge.
   159  	Response []byte
   160  	// An 8-byte array of unsigned char that contains the client's ClientChallenge, as defined in section 3.1.5.1.2.
   161  	ChallengeFromClient []byte
   162  }
   163  
   164  func ReadLmV2Response(bytes []byte) (*LmV2Response, error) {
   165  
   166  	// [Psiphon]
   167  	// Don't panic on malformed remote input.
   168  	if len(bytes) < 24 {
   169  		return nil, errors.New("invalid LM v2 response")
   170  	}
   171  
   172  	r := new(LmV2Response)
   173  	r.Response = bytes[0:16]
   174  	r.ChallengeFromClient = bytes[16:24]
   175  	return r, nil
   176  }
   177  
   178  func (l *LmV2Response) String() string {
   179  	var buffer bytes.Buffer
   180  
   181  	buffer.WriteString("LM v2 Response\n")
   182  	buffer.WriteString(fmt.Sprintf("Response: %s\n", hex.EncodeToString(l.Response)))
   183  	buffer.WriteString(fmt.Sprintf("ChallengeFromClient: %s\n", hex.EncodeToString(l.ChallengeFromClient)))
   184  
   185  	return buffer.String()
   186  }