1 package org.metricshub.winrm.service.client.auth.ntlm;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import org.apache.commons.codec.binary.Base64;
24 import org.apache.http.impl.auth.NTLMEngineException;
25
26
27
28
29
30
31
32
33 class NTLMMessage {
34
35
36 private static final byte[] SIGNATURE;
37
38 static {
39 final byte[] bytesWithoutNull = "NTLMSSP".getBytes(NTLMEngineUtils.DEFAULT_CHARSET);
40 final byte[] target = new byte[bytesWithoutNull.length + 1];
41 System.arraycopy(bytesWithoutNull, 0, target, 0, bytesWithoutNull.length);
42 target[bytesWithoutNull.length] = (byte) 0x00;
43
44 SIGNATURE = target;
45 }
46
47
48 protected byte[] messageContents = null;
49
50
51 protected int currentOutputPosition = 0;
52
53
54 NTLMMessage() {}
55
56
57 NTLMMessage(final byte[] message, final int expectedType) throws NTLMEngineException {
58 messageContents = message;
59
60 if (messageContents.length < SIGNATURE.length) {
61 throw new NTLMEngineException("NTLM message decoding error - packet too short");
62 }
63 int i = 0;
64 while (i < SIGNATURE.length) {
65 if (messageContents[i] != SIGNATURE[i]) {
66 throw new NTLMEngineException("NTLM message expected - instead got unrecognized bytes");
67 }
68 i++;
69 }
70
71
72 final int type = readULong(SIGNATURE.length);
73 if (type != expectedType) {
74 throw new NTLMEngineException(
75 String.format("NTLM type %d message expected - instead got type %d", expectedType, type)
76 );
77 }
78
79 currentOutputPosition = messageContents.length;
80 }
81
82
83 int readULong(final int position) {
84 return readULong(messageContents, position);
85 }
86
87 static int readULong(final byte[] src, final int index) {
88 if (src.length < index + 4) {
89 return 0;
90 }
91 return (
92 (src[index] & 0xff) |
93 ((src[index + 1] & 0xff) << 8) |
94 ((src[index + 2] & 0xff) << 16) |
95 ((src[index + 3] & 0xff) << 24)
96 );
97 }
98
99
100
101
102
103
104
105
106
107 void prepareResponse(final int maxlength, final int messageType) {
108 messageContents = new byte[maxlength];
109 currentOutputPosition = 0;
110 addBytes(SIGNATURE);
111 addULong(messageType);
112 }
113
114
115
116
117
118
119
120 private void addByte(final byte b) {
121 messageContents[currentOutputPosition] = b;
122 currentOutputPosition++;
123 }
124
125
126
127
128
129
130
131 void addBytes(final byte[] bytes) {
132 if (bytes == null) {
133 return;
134 }
135 for (final byte b : bytes) {
136 messageContents[currentOutputPosition] = b;
137 currentOutputPosition++;
138 }
139 }
140
141
142 void addUShort(final int value) {
143 addByte((byte) (value & 0xff));
144 addByte((byte) ((value >> 8) & 0xff));
145 }
146
147
148 void addULong(final int value) {
149 addByte((byte) (value & 0xff));
150 addByte((byte) ((value >> 8) & 0xff));
151 addByte((byte) ((value >> 16) & 0xff));
152 addByte((byte) ((value >> 24) & 0xff));
153 }
154
155
156
157
158
159
160
161 String getResponse() {
162 return new String(Base64.encodeBase64(getBytes()), NTLMEngineUtils.DEFAULT_CHARSET);
163 }
164
165 private byte[] getBytes() {
166 if (messageContents == null) {
167 buildMessage();
168 }
169
170 if (messageContents.length > currentOutputPosition) {
171 final byte[] tmp = new byte[currentOutputPosition];
172 System.arraycopy(messageContents, 0, tmp, 0, currentOutputPosition);
173 messageContents = tmp;
174 }
175 return messageContents;
176 }
177
178 protected void buildMessage() {
179 throw new RuntimeException("Message builder not implemented for " + getClass().getName());
180 }
181 }