View Javadoc
1   package org.metricshub.winrm.service.client.encryption;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * WinRM Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 - 2024 Metricshub
8    * ჻჻჻჻჻჻
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   *
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
21   */
22  
23  /**
24   * Cryptography support - MD4. The following class was based loosely on the
25   * RFC and on code found at http://www.cs.umd.edu/~harry/jotp/src/md.java.
26   * Code correctness was verified by looking at MD4.java from the jcifs
27   * library (http://jcifs.samba.org). It was massaged extensively to the
28   * final form found here by Karl Wright (kwright@metacarta.com).
29   *
30   * Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
31   * release 0.12.3 @link https://github.com/cloudsoft/winrm4j
32   * io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
33   */
34  public class MD4 {
35  
36  	private int a = 0x67452301;
37  	private int b = 0xefcdab89;
38  	private int c = 0x98badcfe;
39  	private int d = 0x10325476;
40  	private long count = 0L;
41  	private final byte[] dataBuffer = new byte[64];
42  
43  	void update(final byte[] input) {
44  		// We always deal with 512 bits at a time. Correspondingly, there is
45  		// a buffer 64 bytes long that we write data into until it gets
46  		// full.
47  		int curBufferPos = (int) (count & 63L);
48  		int inputIndex = 0;
49  		while (input.length - inputIndex + curBufferPos >= dataBuffer.length) {
50  			// We have enough data to do the next step. Do a partial copy
51  			// and a transform, updating inputIndex and curBufferPos
52  			// accordingly
53  			final int transferAmt = dataBuffer.length - curBufferPos;
54  			System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
55  			count += transferAmt;
56  			curBufferPos = 0;
57  			inputIndex += transferAmt;
58  			processBuffer();
59  		}
60  
61  		// If there's anything left, copy it into the buffer and leave it.
62  		// We know there's not enough left to process.
63  		if (inputIndex < input.length) {
64  			final int transferAmt = input.length - inputIndex;
65  			System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
66  			count += transferAmt;
67  			curBufferPos += transferAmt;
68  		}
69  	}
70  
71  	byte[] getOutput() {
72  		// Feed pad/length data into engine. This must round out the input
73  		// to a multiple of 512 bits.
74  		final int bufferIndex = (int) (count & 63L);
75  		final int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex);
76  		final byte[] postBytes = new byte[padLen + 8];
77  		// Leading 0x80, specified amount of zero padding, then length in
78  		// bits.
79  		postBytes[0] = (byte) 0x80;
80  		// Fill out the last 8 bytes with the length
81  		for (int i = 0; i < 8; i++) {
82  			postBytes[padLen + i] = (byte) ((count * 8) >>> (8 * i));
83  		}
84  
85  		// Update the engine
86  		update(postBytes);
87  
88  		// Calculate final result
89  		final byte[] result = new byte[16];
90  		writeULong(result, a, 0);
91  		writeULong(result, b, 4);
92  		writeULong(result, c, 8);
93  		writeULong(result, d, 12);
94  		return result;
95  	}
96  
97  	private static void writeULong(final byte[] buffer, final int value, final int offset) {
98  		buffer[offset] = (byte) (value & 0xff);
99  		buffer[offset + 1] = (byte) ((value >> 8) & 0xff);
100 		buffer[offset + 2] = (byte) ((value >> 16) & 0xff);
101 		buffer[offset + 3] = (byte) ((value >> 24) & 0xff);
102 	}
103 
104 	private void processBuffer() {
105 		// Convert current buffer to 16 ulongs
106 		final int[] d = new int[16];
107 
108 		for (int i = 0; i < 16; i++) {
109 			d[i] =
110 				(dataBuffer[i * 4] & 0xff) +
111 				((dataBuffer[i * 4 + 1] & 0xff) << 8) +
112 				((dataBuffer[i * 4 + 2] & 0xff) << 16) +
113 				((dataBuffer[i * 4 + 3] & 0xff) << 24);
114 		}
115 
116 		// Do a round of processing
117 		final int aa = a;
118 		final int bb = b;
119 		final int cc = c;
120 		final int dd = this.d;
121 		round1(d);
122 		round2(d);
123 		round3(d);
124 		a += aa;
125 		b += bb;
126 		c += cc;
127 		this.d += dd;
128 	}
129 
130 	private void round1(final int[] d) {
131 		a = rotintlft((a + f(b, c, this.d) + d[0]), 3);
132 		this.d = rotintlft((this.d + f(a, b, c) + d[1]), 7);
133 		c = rotintlft((c + f(this.d, a, b) + d[2]), 11);
134 		b = rotintlft((b + f(c, this.d, a) + d[3]), 19);
135 
136 		a = rotintlft((a + f(b, c, this.d) + d[4]), 3);
137 		this.d = rotintlft((this.d + f(a, b, c) + d[5]), 7);
138 		c = rotintlft((c + f(this.d, a, b) + d[6]), 11);
139 		b = rotintlft((b + f(c, this.d, a) + d[7]), 19);
140 
141 		a = rotintlft((a + f(b, c, this.d) + d[8]), 3);
142 		this.d = rotintlft((this.d + f(a, b, c) + d[9]), 7);
143 		c = rotintlft((c + f(this.d, a, b) + d[10]), 11);
144 		b = rotintlft((b + f(c, this.d, a) + d[11]), 19);
145 
146 		a = rotintlft((a + f(b, c, this.d) + d[12]), 3);
147 		this.d = rotintlft((this.d + f(a, b, c) + d[13]), 7);
148 		c = rotintlft((c + f(this.d, a, b) + d[14]), 11);
149 		b = rotintlft((b + f(c, this.d, a) + d[15]), 19);
150 	}
151 
152 	private void round2(final int[] d) {
153 		a = rotintlft((a + g(b, c, this.d) + d[0] + 0x5a827999), 3);
154 		this.d = rotintlft((this.d + g(a, b, c) + d[4] + 0x5a827999), 5);
155 		c = rotintlft((c + g(this.d, a, b) + d[8] + 0x5a827999), 9);
156 		b = rotintlft((b + g(c, this.d, a) + d[12] + 0x5a827999), 13);
157 
158 		a = rotintlft((a + g(b, c, this.d) + d[1] + 0x5a827999), 3);
159 		this.d = rotintlft((this.d + g(a, b, c) + d[5] + 0x5a827999), 5);
160 		c = rotintlft((c + g(this.d, a, b) + d[9] + 0x5a827999), 9);
161 		b = rotintlft((b + g(c, this.d, a) + d[13] + 0x5a827999), 13);
162 
163 		a = rotintlft((a + g(b, c, this.d) + d[2] + 0x5a827999), 3);
164 		this.d = rotintlft((this.d + g(a, b, c) + d[6] + 0x5a827999), 5);
165 		c = rotintlft((c + g(this.d, a, b) + d[10] + 0x5a827999), 9);
166 		b = rotintlft((b + g(c, this.d, a) + d[14] + 0x5a827999), 13);
167 
168 		a = rotintlft((a + g(b, c, this.d) + d[3] + 0x5a827999), 3);
169 		this.d = rotintlft((this.d + g(a, b, c) + d[7] + 0x5a827999), 5);
170 		c = rotintlft((c + g(this.d, a, b) + d[11] + 0x5a827999), 9);
171 		b = rotintlft((b + g(c, this.d, a) + d[15] + 0x5a827999), 13);
172 	}
173 
174 	private void round3(final int[] d) {
175 		a = rotintlft((a + h(b, c, this.d) + d[0] + 0x6ed9eba1), 3);
176 		this.d = rotintlft((this.d + h(a, b, c) + d[8] + 0x6ed9eba1), 9);
177 		c = rotintlft((c + h(this.d, a, b) + d[4] + 0x6ed9eba1), 11);
178 		b = rotintlft((b + h(c, this.d, a) + d[12] + 0x6ed9eba1), 15);
179 
180 		a = rotintlft((a + h(b, c, this.d) + d[2] + 0x6ed9eba1), 3);
181 		this.d = rotintlft((this.d + h(a, b, c) + d[10] + 0x6ed9eba1), 9);
182 		c = rotintlft((c + h(this.d, a, b) + d[6] + 0x6ed9eba1), 11);
183 		b = rotintlft((b + h(c, this.d, a) + d[14] + 0x6ed9eba1), 15);
184 
185 		a = rotintlft((a + h(b, c, this.d) + d[1] + 0x6ed9eba1), 3);
186 		this.d = rotintlft((this.d + h(a, b, c) + d[9] + 0x6ed9eba1), 9);
187 		c = rotintlft((c + h(this.d, a, b) + d[5] + 0x6ed9eba1), 11);
188 		b = rotintlft((b + h(c, this.d, a) + d[13] + 0x6ed9eba1), 15);
189 
190 		a = rotintlft((a + h(b, c, this.d) + d[3] + 0x6ed9eba1), 3);
191 		this.d = rotintlft((this.d + h(a, b, c) + d[11] + 0x6ed9eba1), 9);
192 		c = rotintlft((c + h(this.d, a, b) + d[7] + 0x6ed9eba1), 11);
193 		b = rotintlft((b + h(c, this.d, a) + d[15] + 0x6ed9eba1), 15);
194 	}
195 
196 	private static int f(final int x, final int y, final int z) {
197 		return ((x & y) | (~x & z));
198 	}
199 
200 	private static int g(final int x, final int y, final int z) {
201 		return ((x & y) | (x & z) | (y & z));
202 	}
203 
204 	private static int h(final int x, final int y, final int z) {
205 		return (x ^ y ^ z);
206 	}
207 
208 	private static int rotintlft(final int val, final int numbits) {
209 		return ((val << numbits) | (val >>> (32 - numbits)));
210 	}
211 }