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 java.util.Arrays;
24 import java.util.Objects;
25 import java.util.concurrent.atomic.AtomicLong;
26 import javax.crypto.Cipher;
27 import org.apache.http.HttpEntityEnclosingRequest;
28 import org.apache.http.HttpRequest;
29 import org.apache.http.auth.NTCredentials;
30 import org.metricshub.winrm.service.client.encryption.EncryptionAwareHttpEntity;
31 import org.metricshub.winrm.service.client.encryption.EncryptionUtils;
32
33
34
35
36
37
38 public class NTCredentialsWithEncryption extends NTCredentials {
39
40 private static final long serialVersionUID = 1L;
41
42 private boolean isAuthenticated = false;
43 private long negotiateFlags;
44 private byte[] clientSigningKey;
45 private byte[] serverSigningKey;
46 private byte[] clientSealingKey;
47 private byte[] serverSealingKey;
48 private AtomicLong sequenceNumberIncoming = new AtomicLong(-1);
49 private AtomicLong sequenceNumberOutgoing = new AtomicLong(-1);
50
51 public NTCredentialsWithEncryption(
52 final String userName,
53 final String password,
54 final String workstation,
55 final String domain
56 ) {
57 super(userName, password, workstation, domain);
58 }
59
60 public boolean isAuthenticated() {
61 return isAuthenticated;
62 }
63
64 public void setIsAuthenticated(boolean isAuthenticated) {
65 this.isAuthenticated = isAuthenticated;
66 }
67
68 public void setClientSigningKey(byte[] clientSigningKey) {
69 this.clientSigningKey = clientSigningKey;
70 }
71
72 public void setServerSigningKey(byte[] serverSigningKey) {
73 this.serverSigningKey = serverSigningKey;
74 }
75
76 public byte[] getClientSigningKey() {
77 return clientSigningKey;
78 }
79
80 public byte[] getServerSigningKey() {
81 return serverSigningKey;
82 }
83
84 public void setClientSealingKey(byte[] clientSealingKey) {
85 this.clientSealingKey = clientSealingKey;
86 }
87
88 public void setServerSealingKey(byte[] serverSealingKey) {
89 this.serverSealingKey = serverSealingKey;
90 }
91
92 public byte[] getClientSealingKey() {
93 return clientSealingKey;
94 }
95
96 public byte[] getServerSealingKey() {
97 return serverSealingKey;
98 }
99
100 public long getNegotiateFlags() {
101 return negotiateFlags;
102 }
103
104 public boolean hasNegotiateFlag(long flag) {
105 return (getNegotiateFlags() & flag) == flag;
106 }
107
108 public void setNegotiateFlags(long negotiateFlags) {
109 this.negotiateFlags = negotiateFlags;
110 }
111
112 public AtomicLong getSequenceNumberIncoming() {
113 return sequenceNumberIncoming;
114 }
115
116 public AtomicLong getSequenceNumberOutgoing() {
117 return sequenceNumberOutgoing;
118 }
119
120 private transient Cipher encryptor;
121
122 public Cipher getStatefulEncryptor() {
123 if (encryptor == null) {
124 encryptor = EncryptionUtils.arc4(getClientSealingKey());
125 }
126 return encryptor;
127 }
128
129 private transient Cipher decryptor;
130
131 public Cipher getStatefulDecryptor() {
132 if (decryptor == null) {
133 decryptor = EncryptionUtils.arc4(getServerSealingKey());
134 }
135 return decryptor;
136 }
137
138 void resetEncryption(final HttpRequest request) {
139 setIsAuthenticated(false);
140 clientSealingKey = null;
141 clientSigningKey = null;
142 serverSealingKey = null;
143 serverSigningKey = null;
144 encryptor = null;
145 decryptor = null;
146 sequenceNumberIncoming.set(-1);
147 sequenceNumberOutgoing.set(-1);
148
149 if (
150 request instanceof HttpEntityEnclosingRequest &&
151 ((HttpEntityEnclosingRequest) request).getEntity() instanceof EncryptionAwareHttpEntity
152 ) {
153 ((EncryptionAwareHttpEntity) ((HttpEntityEnclosingRequest) request).getEntity()).refreshHeaders(
154 (HttpEntityEnclosingRequest) request
155 );
156 }
157 }
158
159 void initEncryption(final Type3Message signAndSealData, final HttpRequest request) {
160 setIsAuthenticated(true);
161 if (signAndSealData != null && signAndSealData.getExportedSessionKey() != null) {
162 new NtlmKeys(signAndSealData).apply(this);
163 }
164 if (
165 request instanceof HttpEntityEnclosingRequest &&
166 ((HttpEntityEnclosingRequest) request).getEntity() instanceof EncryptionAwareHttpEntity
167 ) {
168 ((EncryptionAwareHttpEntity) ((HttpEntityEnclosingRequest) request).getEntity()).refreshHeaders(
169 (HttpEntityEnclosingRequest) request
170 );
171 }
172 }
173
174 @Override
175 public String toString() {
176 return getClass().getSimpleName() + super.toString() + "{auth=" + isAuthenticated() + "}";
177 }
178
179 @Override
180 public int hashCode() {
181 final int prime = 31;
182 int result = super.hashCode();
183 result = prime * result + Arrays.hashCode(clientSealingKey);
184 result = prime * result + Arrays.hashCode(clientSigningKey);
185 result = prime * result + Arrays.hashCode(serverSealingKey);
186 result = prime * result + Arrays.hashCode(serverSigningKey);
187 result =
188 prime * result + Objects.hash(isAuthenticated, negotiateFlags, sequenceNumberIncoming, sequenceNumberOutgoing);
189 return result;
190 }
191
192 @Override
193 public boolean equals(Object obj) {
194 if (this == obj) return true;
195 if (!super.equals(obj)) return false;
196 if (!(obj instanceof NTCredentialsWithEncryption)) return false;
197 NTCredentialsWithEncryption other = (NTCredentialsWithEncryption) obj;
198 return (
199 Arrays.equals(clientSealingKey, other.clientSealingKey) &&
200 Arrays.equals(clientSigningKey, other.clientSigningKey) &&
201 isAuthenticated == other.isAuthenticated &&
202 negotiateFlags == other.negotiateFlags &&
203 Objects.equals(sequenceNumberIncoming, other.sequenceNumberIncoming) &&
204 Objects.equals(sequenceNumberOutgoing, other.sequenceNumberOutgoing) &&
205 Arrays.equals(serverSealingKey, other.serverSealingKey) &&
206 Arrays.equals(serverSigningKey, other.serverSigningKey)
207 );
208 }
209 }