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 }