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 import java.security.MessageDigest;
24
25 /**
26 * Cryptography support - HMACMD5 - algorithmically based on various web
27 * resources by Karl Wright
28 *
29 * Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
30 * release 0.12.3 @link https://github.com/cloudsoft/winrm4j
31 * io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
32 */
33 public class HMACMD5 {
34
35 private final byte[] ipad;
36 private final byte[] opad;
37 private final MessageDigest md5;
38
39 HMACMD5(final byte[] input) {
40 byte[] key = input;
41 md5 = EncryptionUtils.getMD5();
42
43 // Initialize the pad buffers with the key
44 ipad = new byte[64];
45 opad = new byte[64];
46
47 int keyLength = key.length;
48 if (keyLength > 64) {
49 // Use MD5 of the key instead, as described in RFC 2104
50 md5.update(key);
51 key = md5.digest();
52 keyLength = key.length;
53 }
54 int i = 0;
55 while (i < keyLength) {
56 ipad[i] = (byte) (key[i] ^ (byte) 0x36);
57 opad[i] = (byte) (key[i] ^ (byte) 0x5c);
58 i++;
59 }
60 while (i < 64) {
61 ipad[i] = (byte) 0x36;
62 opad[i] = (byte) 0x5c;
63 i++;
64 }
65
66 // Very important: processChallenge the digest with the ipad buffer
67 md5.reset();
68 md5.update(ipad);
69 }
70
71 /** Grab the current digest. This is the "answer". */
72 byte[] getOutput() {
73 final byte[] digest = md5.digest();
74 md5.update(opad);
75 return md5.digest(digest);
76 }
77
78 /** Update by adding a complete array */
79 void update(final byte[] input) {
80 md5.update(input);
81 }
82 }