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