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"
31
static guchar NTLM_NEGOTIATE_MESSAGE[] = {
32
'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00,
33
0x01, 0x00, 0x00, 0x00, 0x06, 0x82, 0x00, 0x00,
34
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36
0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
37
0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00
43
* Creates an NTLM Type 1 (Negotiate) message
45
* Return value: the message
48
xntlm_negotiate (void)
52
message = g_byte_array_new ();
53
g_byte_array_append (message, NTLM_NEGOTIATE_MESSAGE,
54
sizeof (NTLM_NEGOTIATE_MESSAGE));
58
#define GET_SHORTY(p) ((p)[0] + ((p)[1] << 8))
61
strip_dup (guchar *mem, gint len)
63
gchar *buf = g_malloc (len / 2 + 1), *p = buf;
76
#define NTLM_CHALLENGE_NONCE_POS 24
77
#define NTLM_CHALLENGE_NONCE_LEN 8
79
#define NTLM_CHALLENGE_DATA_OFFSET_POS 44
80
#define NTLM_CHALLENGE_DATA_LENGTH_POS 40
82
#define NTLM_CHALLENGE_DATA_NT_DOMAIN 2
83
#define NTLM_CHALLENGE_DATA_W2K_DOMAIN 4
85
#define NTLM_CHALLENGE_BASE_SIZE 48
88
* xntlm_parse_challenge:
89
* @challenge: buffer containing an NTLM Type 2 (Challenge) message
90
* @len: the length of @challenge
91
* @nonce: return variable for the challenge nonce, or %NULL
92
* @nt_domain: return variable for the server NT domain, or %NULL
93
* @w2k_domain: return variable for the server W2k domain, or %NULL
95
* Attempts to parse the challenge in @challenge. If @nonce is
96
* non-%NULL, the 8-byte nonce from @challenge will be returned in it.
97
* Likewise, if @nt_domain and/or @w2k_domain are non-%NULL, the
98
* server's domain names will be returned in them. The strings
99
* returned must be freed with g_free().
101
* Return value: %TRUE if the challenge could be parsed,
105
xntlm_parse_challenge (gpointer challenge, gint len, gchar **nonce,
106
gchar **nt_domain, gchar **w2k_domain)
108
guchar *chall = (guchar *)challenge;
109
gint off, dlen, doff, type;
111
if (len < NTLM_CHALLENGE_BASE_SIZE)
114
off = GET_SHORTY (chall + NTLM_CHALLENGE_DATA_OFFSET_POS);
115
dlen = GET_SHORTY (chall + NTLM_CHALLENGE_DATA_LENGTH_POS);
116
if (len < off + dlen)
120
*nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_POS,
121
NTLM_CHALLENGE_NONCE_LEN);
124
if (!nt_domain && !w2k_domain)
127
while (off < len - 4) {
128
type = GET_SHORTY (chall + off);
129
dlen = GET_SHORTY (chall + off + 2);
131
if (doff + dlen > len)
135
case NTLM_CHALLENGE_DATA_NT_DOMAIN:
137
*nt_domain = strip_dup (chall + doff, dlen);
139
case NTLM_CHALLENGE_DATA_W2K_DOMAIN:
141
*w2k_domain = strip_dup (chall + doff, dlen);
152
ntlm_set_string (GByteArray *ba, gint offset, const gchar *data, gint len)
154
ba->data[offset ] = ba->data[offset + 2] = len & 0xFF;
155
ba->data[offset + 1] = ba->data[offset + 3] = (len >> 8) & 0xFF;
156
ba->data[offset + 4] = ba->len & 0xFF;
157
ba->data[offset + 5] = (ba->len >> 8) & 0xFF;
158
g_byte_array_append (ba, (guint8 *) data, len);
161
static void ntlm_lanmanager_hash (const gchar *password, gchar hash[21]);
162
static void ntlm_nt_hash (const gchar *password, gchar hash[21]);
163
static void ntlm_calc_response (const guchar key[21],
164
const guchar plaintext[8],
167
static guchar NTLM_RESPONSE_MESSAGE_HEADER[] = {
168
'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00,
169
0x03, 0x00, 0x00, 0x00, 0x02, 0x82, 0x00, 0x00
172
#define NTLM_RESPONSE_BASE_SIZE 64
173
#define NTLM_RESPONSE_LM_RESP_OFFSET 12
174
#define NTLM_RESPONSE_NT_RESP_OFFSET 20
175
#define NTLM_RESPONSE_DOMAIN_OFFSET 28
176
#define NTLM_RESPONSE_USER_OFFSET 36
177
#define NTLM_RESPONSE_WORKSTATION_OFFSET 44
180
* xntlm_authenticate:
181
* @nonce: the nonce from an NTLM Type 2 (Challenge) message
182
* @domain: the NT domain to authenticate against
183
* @user: the name of the user in @domain
184
* @password: @user's password
185
* @workstation: the name of the local workstation authenticated
188
* Generates an NTLM Type 3 (Authenticate) message from the given
189
* data. @workstation is provided for completeness, but can basically
190
* always be left %NULL.
192
* Return value: the NTLM Type 3 message
195
xntlm_authenticate (const gchar *nonce, const gchar *domain,
196
const gchar *user, const gchar *password,
197
const gchar *workstation)
200
guchar hash[21], lm_resp[24], nt_resp[24];
205
message = g_byte_array_new ();
207
ntlm_lanmanager_hash (password, (gchar *) hash);
208
ntlm_calc_response (hash, (guchar *) nonce, lm_resp);
209
ntlm_nt_hash (password, (gchar *) hash);
210
ntlm_calc_response (hash, (guchar *) nonce, nt_resp);
212
g_byte_array_set_size (message, NTLM_RESPONSE_BASE_SIZE);
213
memset (message->data, 0, NTLM_RESPONSE_BASE_SIZE);
214
memcpy (message->data, NTLM_RESPONSE_MESSAGE_HEADER,
215
sizeof (NTLM_RESPONSE_MESSAGE_HEADER));
217
ntlm_set_string (message, NTLM_RESPONSE_DOMAIN_OFFSET,
218
domain, strlen (domain));
219
ntlm_set_string (message, NTLM_RESPONSE_USER_OFFSET,
220
user, strlen (user));
221
ntlm_set_string (message, NTLM_RESPONSE_WORKSTATION_OFFSET,
222
workstation, strlen (workstation));
223
ntlm_set_string (message, NTLM_RESPONSE_LM_RESP_OFFSET,
224
(gchar *) lm_resp, sizeof (lm_resp));
225
ntlm_set_string (message, NTLM_RESPONSE_NT_RESP_OFFSET,
226
(gchar *) nt_resp, sizeof (nt_resp));
232
setup_schedule (const guchar *key_56, XNTLM_DES_KS ks)
237
key[0] = (key_56[0]);
238
key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
239
key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
240
key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
241
key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
242
key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
243
key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
244
key[7] = ((key_56[6] << 1) & 0xFF);
247
for (i = 0; i < 8; i++) {
248
for (c = bit = 0; bit < 8; bit++)
249
if (key [i] & (1 << bit))
255
xntlm_deskey (ks, key, XNTLM_DES_ENCRYPT);
258
static guchar LM_PASSWORD_MAGIC[] = {
259
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25,
260
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25,
261
0x00, 0x00, 0x00, 0x00, 0x00
265
ntlm_lanmanager_hash (const gchar *password, gchar hash[21])
267
guchar lm_password [15];
271
for (i = 0; i < 14 && password [i]; i++)
272
lm_password [i] = toupper ((guchar) password [i]);
274
for (; i < sizeof (lm_password); i++)
275
lm_password [i] = '\0';
277
memcpy (hash, LM_PASSWORD_MAGIC, sizeof (LM_PASSWORD_MAGIC));
279
setup_schedule (lm_password, ks);
280
xntlm_des (ks, (guchar *) hash);
282
setup_schedule (lm_password + 7, ks);
283
xntlm_des (ks, (guchar *) hash + 8);
287
ntlm_nt_hash (const gchar *password, gchar hash[21])
291
p = buf = g_malloc (strlen (password) * 2);
298
xntlm_md4sum (buf, p - buf, (guchar *) hash);
299
memset (hash + 16, 0, 5);
305
ntlm_calc_response (const guchar key[21], const guchar plaintext[8],
310
memcpy (results, plaintext, 8);
311
memcpy (results + 8, plaintext, 8);
312
memcpy (results + 16, plaintext, 8);
314
setup_schedule (key, ks);
315
xntlm_des (ks, results);
317
setup_schedule (key + 7, ks);
318
xntlm_des (ks, results + 8);
320
setup_schedule (key + 14, ks);
321
xntlm_des (ks, results + 16);