1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Copyright (C) 2001-2004 Novell, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
25 #include "xntlm-des.h"
26 #include "xntlm-md4.h"
32 static unsigned char NTLM_NEGOTIATE_MESSAGE[] = {
33 'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00,
34 0x01, 0x00, 0x00, 0x00, 0x06, 0x82, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
38 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00
44 * Creates an NTLM Type 1 (Negotiate) message
46 * Return value: the message
49 xntlm_negotiate (void)
53 message = g_byte_array_new ();
54 g_byte_array_append (message, NTLM_NEGOTIATE_MESSAGE,
55 sizeof (NTLM_NEGOTIATE_MESSAGE));
60 #define GET_SHORTY(p) ((p)[0] + ((p)[1] << 8))
63 strip_dup (unsigned char *mem, int len)
65 char *buf = g_malloc (len / 2 + 1), *p = buf;
78 #define NTLM_CHALLENGE_NONCE_POS 24
79 #define NTLM_CHALLENGE_NONCE_LEN 8
81 #define NTLM_CHALLENGE_DATA_OFFSET_POS 44
82 #define NTLM_CHALLENGE_DATA_LENGTH_POS 40
84 #define NTLM_CHALLENGE_DATA_NT_DOMAIN 2
85 #define NTLM_CHALLENGE_DATA_W2K_DOMAIN 4
87 #define NTLM_CHALLENGE_BASE_SIZE 48
90 * xntlm_parse_challenge:
91 * @challenge: buffer containing an NTLM Type 2 (Challenge) message
92 * @len: the length of @challenge
93 * @nonce: return variable for the challenge nonce, or %NULL
94 * @nt_domain: return variable for the server NT domain, or %NULL
95 * @w2k_domain: return variable for the server W2k domain, or %NULL
97 * Attempts to parse the challenge in @challenge. If @nonce is
98 * non-%NULL, the 8-byte nonce from @challenge will be returned in it.
99 * Likewise, if @nt_domain and/or @w2k_domain are non-%NULL, the
100 * server's domain names will be returned in them. The strings
101 * returned must be freed with g_free().
103 * Return value: %TRUE if the challenge could be parsed,
107 xntlm_parse_challenge (gpointer challenge, int len, char **nonce,
108 char **nt_domain, char **w2k_domain)
110 unsigned char *chall = (unsigned char *)challenge;
111 int off, dlen, doff, type;
113 if (len < NTLM_CHALLENGE_BASE_SIZE)
116 off = GET_SHORTY (chall + NTLM_CHALLENGE_DATA_OFFSET_POS);
117 dlen = GET_SHORTY (chall + NTLM_CHALLENGE_DATA_LENGTH_POS);
118 if (len < off + dlen)
122 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_POS,
123 NTLM_CHALLENGE_NONCE_LEN);
126 if (!nt_domain && !w2k_domain)
129 while (off < len - 4) {
130 type = GET_SHORTY (chall + off);
131 dlen = GET_SHORTY (chall + off + 2);
133 if (doff + dlen > len)
137 case NTLM_CHALLENGE_DATA_NT_DOMAIN:
139 *nt_domain = strip_dup (chall + doff, dlen);
141 case NTLM_CHALLENGE_DATA_W2K_DOMAIN:
143 *w2k_domain = strip_dup (chall + doff, dlen);
155 ntlm_set_string (GByteArray *ba, int offset, const char *data, int len)
157 ba->data[offset ] = ba->data[offset + 2] = len & 0xFF;
158 ba->data[offset + 1] = ba->data[offset + 3] = (len >> 8) & 0xFF;
159 ba->data[offset + 4] = ba->len & 0xFF;
160 ba->data[offset + 5] = (ba->len >> 8) & 0xFF;
161 g_byte_array_append (ba, data, len);
164 static void ntlm_lanmanager_hash (const char *password, char hash[21]);
165 static void ntlm_nt_hash (const char *password, char hash[21]);
166 static void ntlm_calc_response (const guchar key[21],
167 const guchar plaintext[8],
170 static unsigned char NTLM_RESPONSE_MESSAGE_HEADER[] = {
171 'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00,
172 0x03, 0x00, 0x00, 0x00, 0x02, 0x82, 0x00, 0x00
175 #define NTLM_RESPONSE_BASE_SIZE 64
176 #define NTLM_RESPONSE_LM_RESP_OFFSET 12
177 #define NTLM_RESPONSE_NT_RESP_OFFSET 20
178 #define NTLM_RESPONSE_DOMAIN_OFFSET 28
179 #define NTLM_RESPONSE_USER_OFFSET 36
180 #define NTLM_RESPONSE_WORKSTATION_OFFSET 44
183 * xntlm_authenticate:
184 * @nonce: the nonce from an NTLM Type 2 (Challenge) message
185 * @domain: the NT domain to authenticate against
186 * @user: the name of the user in @domain
187 * @password: @user's password
188 * @workstation: the name of the local workstation authenticated
191 * Generates an NTLM Type 3 (Authenticate) message from the given
192 * data. @workstation is provided for completeness, but can basically
193 * always be left %NULL.
195 * Return value: the NTLM Type 3 message
198 xntlm_authenticate (const char *nonce, const char *domain,
199 const char *user, const char *password,
200 const char *workstation)
203 guchar hash[21], lm_resp[24], nt_resp[24];
208 message = g_byte_array_new ();
210 ntlm_lanmanager_hash (password, hash);
211 ntlm_calc_response (hash, nonce, lm_resp);
212 ntlm_nt_hash (password, hash);
213 ntlm_calc_response (hash, nonce, nt_resp);
215 g_byte_array_set_size (message, NTLM_RESPONSE_BASE_SIZE);
216 memset (message->data, 0, NTLM_RESPONSE_BASE_SIZE);
217 memcpy (message->data, NTLM_RESPONSE_MESSAGE_HEADER,
218 sizeof (NTLM_RESPONSE_MESSAGE_HEADER));
220 ntlm_set_string (message, NTLM_RESPONSE_DOMAIN_OFFSET,
221 domain, strlen (domain));
222 ntlm_set_string (message, NTLM_RESPONSE_USER_OFFSET,
223 user, strlen (user));
224 ntlm_set_string (message, NTLM_RESPONSE_WORKSTATION_OFFSET,
225 workstation, strlen (workstation));
226 ntlm_set_string (message, NTLM_RESPONSE_LM_RESP_OFFSET,
227 lm_resp, sizeof (lm_resp));
228 ntlm_set_string (message, NTLM_RESPONSE_NT_RESP_OFFSET,
229 nt_resp, sizeof (nt_resp));
236 setup_schedule (const guchar *key_56, XNTLM_DES_KS ks)
241 key[0] = (key_56[0]) ;
242 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
243 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
244 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
245 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
246 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
247 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
248 key[7] = ((key_56[6] << 1) & 0xFF);
251 for (i = 0; i < 8; i++) {
252 for (c = bit = 0; bit < 8; bit++)
253 if (key [i] & (1 << bit))
259 xntlm_deskey (ks, key, XNTLM_DES_ENCRYPT);
262 static unsigned char LM_PASSWORD_MAGIC[] = {
263 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25,
264 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25,
265 0x00, 0x00, 0x00, 0x00, 0x00
269 ntlm_lanmanager_hash (const char *password, char hash[21])
271 guchar lm_password [15];
275 for (i = 0; i < 14 && password [i]; i++)
276 lm_password [i] = toupper ((unsigned char) password [i]);
278 for (; i < sizeof (lm_password); i++)
279 lm_password [i] = '\0';
281 memcpy (hash, LM_PASSWORD_MAGIC, sizeof (LM_PASSWORD_MAGIC));
283 setup_schedule (lm_password, ks);
284 xntlm_des (ks, hash);
286 setup_schedule (lm_password + 7, ks);
287 xntlm_des (ks, hash + 8);
291 ntlm_nt_hash (const char *password, char hash[21])
293 unsigned char *buf, *p;
295 p = buf = g_malloc (strlen (password) * 2);
302 xntlm_md4sum (buf, p - buf, hash);
303 memset (hash + 16, 0, 5);
309 ntlm_calc_response (const guchar key[21], const guchar plaintext[8],
314 memcpy (results, plaintext, 8);
315 memcpy (results + 8, plaintext, 8);
316 memcpy (results + 16, plaintext, 8);
318 setup_schedule (key, ks);
319 xntlm_des (ks, results);
321 setup_schedule (key + 7, ks);
322 xntlm_des (ks, results + 8);
324 setup_schedule (key + 14, ks);
325 xntlm_des (ks, results + 16);