6 * Copyright (C) 2008 Novell, Inc.
7 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
8 * Modify 2007, Anibal Avelar <debianmx@gmail.com>
10 * Implemented with reference to the follow documentation:
11 * - http://davenport.sourceforge.net/ntlm.html
12 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
13 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
15 * hashing done according to description of NTLM on
16 * http://www.innovation.ch/java/ntlm.html
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <sys/types.h>
38 #include <netinet/in.h>
44 #define _LIBC_INTERNAL_
53 #ifdef HAVE_LANGINFO_CODESET
55 #endif /* HAVE_LANGINFO_CODESET */
62 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
64 struct challenge_message
{
65 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
66 guint8 type
; /* 0x02 */
68 short msg_len
; /* 0x28 */
70 guint32 flags
; /* 0x8201 */
76 struct authenticate_message
{
77 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
78 //guint32 type; /* 0x03 */
79 guint8 type
; /* 0x03 */
82 guint16 lm_resp_len1
; /* LanManager response length (always 0x18)*/
83 guint16 lm_resp_len2
; /* LanManager response length (always 0x18)*/
84 //guint32 lm_resp_off; /* LanManager response offset */
85 guint16 lm_resp_off
; /* LanManager response offset */
88 /* NtChallengeResponseFields */
89 guint16 nt_resp_len1
; /* NT response length (always 0x18) */
90 guint16 nt_resp_len2
; /* NT response length (always 0x18) */
91 //guint32 nt_resp_off; /* NT response offset */
92 guint16 nt_resp_off
; /* NT response offset */
95 /* DomainNameFields */
96 guint16 dom_len1
; /* domain string length */
97 guint16 dom_len2
; /* domain string length */
98 //guint32 dom_off; /* domain string offset (always 0x40) */
99 guint16 dom_off
; /* domain string offset (always 0x40) */
103 guint16 user_len1
; /* username string length */
104 guint16 user_len2
; /* username string length */
105 //guint32 user_off; /* username string offset */
106 guint16 user_off
; /* username string offset */
109 /* WorkstationFields */
110 guint16 host_len1
; /* host string length */
111 guint16 host_len2
; /* host string length */
112 //guint32 host_off; /* host string offset */
113 guint16 host_off
; /* host string offset */
116 /* EncryptedRandomSessionKeyFields */
130 /* guint32 flags2; unknown, used in windows messenger
134 guint8 dom
[*]; /* domain string (unicode UTF-16LE) */
135 guint8 user
[*]; /* username string (unicode UTF-16LE) */
136 guint8 host
[*]; /* host string (unicode UTF-16LE) */
137 guint8 lm_resp
[*]; /* LanManager response */
138 guint8 nt_resp
[*]; /* NT response */
142 /* Private Methods */
144 static void setup_des_key(const unsigned char key_56
[], char *key
)
147 key
[1] = ((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1);
148 key
[2] = ((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2);
149 key
[3] = ((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3);
150 key
[4] = ((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4);
151 key
[5] = ((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5);
152 key
[6] = ((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6);
153 key
[7] = (key_56
[6] << 1) & 0xFF;
156 static void des_ecb_encrypt(const char *plaintext
, char *result
, const char *key
)
158 PurpleCipher
*cipher
;
159 PurpleCipherContext
*context
;
162 cipher
= purple_ciphers_find_cipher("des");
163 context
= purple_cipher_context_new(cipher
, NULL
);
164 purple_cipher_context_set_key(context
, (guchar
*)key
);
165 purple_cipher_context_encrypt(context
, (guchar
*)plaintext
, 8, (guchar
*)result
, &outlen
);
166 purple_cipher_context_destroy(context
);
170 unicode_strconvcopy(gchar
*dest
, const gchar
*source
, int remlen
)
173 gchar
*inbuf
= (gchar
*) source
;
174 gchar
*outbuf
= dest
;
175 size_t inbytes
= strlen(source
);
176 size_t outbytes
= remlen
;
177 #ifdef HAVE_LANGINFO_CODESET
178 char *sys_cp
= nl_langinfo(CODESET
);
180 char *sys_cp
= SIPE_DEFAULT_CODESET
;
181 #endif /* HAVE_LANGINFO_CODESET */
183 /* fall back to utf-8 */
184 if (!sys_cp
) sys_cp
= "UTF-8";
186 fd
= g_iconv_open("UTF-16LE", sys_cp
);
187 if( fd
== (iconv_t
)-1 ) {
188 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
190 g_iconv(fd
, &inbuf
, &inbytes
, &outbuf
, &outbytes
);
192 return (remlen
- outbytes
);
195 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
197 DES (const char *k
, const char *d
, char * results
)
200 setup_des_key(k
, key
);
201 des_ecb_encrypt(d
, results
, key
);
204 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
206 DESL (char *k
, const char *d
, char * results
)
210 // Copy the first 16 bytes
213 // Zero out the last 5 bytes of the key
214 memset(keys
+ 16, 0, 5);
216 DES(keys
, d
, results
);
217 DES(keys
+ 7, d
, results
+ 8);
218 DES(keys
+ 14, d
, results
+ 16);
222 MD4 (const char * d
, int len
, char * result
)
224 PurpleCipher
* cipher
= purple_ciphers_find_cipher("md4");
225 PurpleCipherContext
* context
= purple_cipher_context_new(cipher
, NULL
);
226 purple_cipher_context_append(context
, (guchar
*)d
, len
);
227 purple_cipher_context_digest(context
, MD4_DIGEST_LEN
, (guchar
*)result
, NULL
);
228 purple_cipher_context_destroy(context
);
233 NTOWFv1 (const char* password
, const char *user
, const char *domain
, char * result
)
235 int len
= 2 * strlen(password
); // utf16 should not be more
236 char *unicode_password
= g_new0(char, len
);
238 len
= unicode_strconvcopy(unicode_password
, password
, len
);
239 MD4 (unicode_password
, len
, result
);
240 g_free(unicode_password
);
244 // MD5 (const char * d, int len, char * result)
246 // PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
247 // PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
248 // purple_cipher_context_append(context, (guchar*)d, len);
249 // purple_cipher_context_digest(context, len, (guchar*)result, NULL);
250 // purple_cipher_context_destroy(context);
254 RC4K (const char * k
, const char * d
, char * result
)
256 PurpleCipherContext
* context
= purple_cipher_context_new_by_name("rc4", NULL
);
257 purple_cipher_context_set_option(context
, "key_len", (gpointer
)16);
258 purple_cipher_context_set_key(context
, k
);
259 purple_cipher_context_encrypt(context
, (const guchar
*)d
, 16, result
, NULL
);
260 purple_cipher_context_destroy(context
);
264 KXKEY (const char * session_base_key
, const char * lm_challenge_resonse
, char * key_exchange_key
)
266 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
267 memcpy(key_exchange_key
, session_base_key
, 16);
270 // This method is only used for NTLM v2 session security w/ enhanced security negotiated
272 SIGNKEY (const char * random_session_key, gboolean client, char * result)
274 char * magic = client
275 ? "session key to client-to-server signing key magic constant"
276 : "session key to server-to-client signing key magic constant";
278 int len = strlen(magic);
279 char md5_input [16 + len];
280 memcpy(md5_input, random_session_key, 16);
281 memcpy(md5_input + 16, magic, len);
283 MD5 (md5_input, len + 16, result);
287 LMOWFv1 (const char *password
, const char *user
, const char *domain
, char *result
)
290 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
291 char uppercase_password
[14];
294 int len
= strlen(password
);
299 // Uppercase password
300 for (i
= 0; i
< len
; i
++) {
301 uppercase_password
[i
] = g_ascii_toupper(password
[i
]);
305 for (; i
< 14; i
++) {
306 uppercase_password
[i
] = 0;
309 DES (uppercase_password
, magic
, result
);
310 DES (uppercase_password
+ 7, magic
, result
+ 8);
314 NONCE(char *buffer
, int num
)
317 for (i
= 0; i
< num
; i
++) {
318 buffer
[i
] = (char)(rand() & 0xff);
322 /* End Private Methods */
324 gchar
*purple_ntlm_parse_challenge(gchar
*challenge
, guint32
*flags
) {
326 static gchar nonce
[8];
327 struct challenge_message
*tmsg
= (struct challenge_message
*)purple_base64_decode((char*)challenge
, &retlen
);
328 memcpy(nonce
, tmsg
->nonce
, 8);
330 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", tmsg
->flags
, (tmsg
->flags
& NEGOTIATE_FLAGS
) == NEGOTIATE_FLAGS
);
333 *flags
= tmsg
->flags
;
340 // print_hex_array(char * msg, int num)
343 // for (k = 0; k < num; k++) {
344 // printf("0x%02X, ", msg[k]&0xff);
350 // print_hex_array_title(char * title, char * msg, int num)
352 // printf("%s:\n", title);
353 // print_hex_array(msg, num);
356 /* source copy from gg's common.c */
357 static guint32 crc32_table
[256];
358 static int crc32_initialized
= 0;
360 static void crc32_make_table()
365 memset(crc32_table
, 0, sizeof(crc32_table
));
367 for (i
= 128; i
; i
>>= 1) {
368 h
= (h
>> 1) ^ ((h
& 1) ? 0xedb88320L
: 0);
370 for (j
= 0; j
< 256; j
+= 2 * i
)
371 crc32_table
[i
+ j
] = crc32_table
[j
] ^ h
;
374 crc32_initialized
= 1;
377 static guint32
crc32(guint32 crc
, const guint8
*buf
, int len
)
379 if (!crc32_initialized
)
388 crc
= (crc
>> 8) ^ crc32_table
[(crc
^ *buf
++) & 0xff];
390 return crc
^ 0xffffffffL
;
396 long crc
= 0L;//crc32(0L, Z_NULL, 0);
397 crc
= crc32(crc
, msg
, strlen(msg
));
398 //char * ptr = (char*) &crc;
399 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
404 purple_ntlm_gen_signature (char * buf
, char * signing_key
, guint32 random_pad
, long sequence
, int key_len
)
407 gint32 plaintext
[] = {0, CRC32(buf
), sequence
};
410 gchar signature
[32];
412 PurpleCipherContext
*rc4
= purple_cipher_context_new_by_name("rc4", NULL
);
413 purple_cipher_context_set_option(rc4
, "key_len", (gpointer
)key_len
);
414 purple_cipher_context_set_key(rc4
, signing_key
);
415 purple_cipher_context_encrypt(rc4
, (const guchar
*)plaintext
, 12, result
+4, NULL
);
416 purple_cipher_context_destroy(rc4
);
418 res_ptr
= (gint32
*)result
;
419 // Highest four bytes are the Version
420 res_ptr
[0] = 0x00000001;
422 // Replace the first four bytes of the ciphertext with a counter value
423 // currently set to this hardcoded value
424 res_ptr
[1] = random_pad
;
426 for (i
= 0, j
= 0; i
< 16; i
++, j
+=2) {
427 g_sprintf(&signature
[j
], "%02X", result
[i
]);
430 //printf("sig: %s\n", signature);
431 return g_strdup(signature
);
435 purple_ntlm_sipe_signature_make (char * msg
, char * signing_key
)
437 return purple_ntlm_gen_signature(msg
, signing_key
, 0, 100, 16);
441 purple_ntlm_verify_signature (char * a
, char * b
)
443 // Make sure the last 16 bytes match
444 gboolean ret
= g_ascii_strncasecmp(a
+ 16, b
+ 16, 16) == 0;
449 purple_ntlm_gen_authenticate(const gchar
**ntlm_key
, const gchar
*user
, const gchar
*password
, const gchar
*hostname
, const gchar
*domain
, const guint8
*nonce
, guint32
*flags
)
451 int msglen
= sizeof(struct authenticate_message
) + 2*(strlen(domain
)
452 + strlen(user
)+ strlen(hostname
) + NTLMSSP_NT_OR_LM_KEY_LEN
)
453 + NTLMSSP_SESSION_KEY_LEN
;
454 struct authenticate_message
*tmsg
= g_malloc0(msglen
);
457 char response_key_lm
[16];
458 char lm_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
459 char response_key_nt
[16];
460 char nt_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
461 char session_base_key
[16];
462 char key_exchange_key
[16];
463 char exported_session_key
[16];
464 char encrypted_random_session_key
[16];
466 /* authenticate message initialization */
467 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
470 /* Set Negotiate Flags */
471 tmsg
->flags
= NEGOTIATE_FLAGS
;
474 tmsg
->dom_off
= sizeof(struct authenticate_message
);
475 tmp
= ((char*) tmsg
) + tmsg
->dom_off
;
476 remlen
= ((char *)tmsg
)+msglen
-tmp
;
477 tmsg
->dom_len1
= tmsg
->dom_len2
= unicode_strconvcopy(tmp
, domain
, remlen
);
478 tmp
+= tmsg
->dom_len1
;
479 remlen
= ((char *)tmsg
)+msglen
-tmp
;
482 tmsg
->user_off
= tmsg
->dom_off
+ tmsg
->dom_len1
;
483 tmsg
->user_len1
= tmsg
->user_len2
= unicode_strconvcopy(tmp
, user
, remlen
);
484 tmp
+= tmsg
->user_len1
;
485 remlen
= ((char *)tmsg
)+msglen
-tmp
;
488 tmsg
->host_off
= tmsg
->user_off
+ tmsg
->user_len1
;
489 tmsg
->host_len1
= tmsg
->host_len2
= unicode_strconvcopy(tmp
, hostname
, remlen
);
490 tmp
+= tmsg
->host_len1
;
493 tmsg
->lm_resp_len1
= tmsg
->lm_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
494 tmsg
->lm_resp_off
= tmsg
->host_off
+ tmsg
->host_len1
;
496 LMOWFv1 (password
, user
, domain
, response_key_lm
);
497 DESL (response_key_lm
, nonce
, lm_challenge_response
);
498 memcpy(tmp
, lm_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
499 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
502 tmsg
->nt_resp_len1
= tmsg
->nt_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
503 tmsg
->nt_resp_off
= tmsg
->lm_resp_off
+ tmsg
->lm_resp_len1
;
505 NTOWFv1 (password
, user
, domain
, response_key_nt
);
506 DESL (response_key_nt
, nonce
, nt_challenge_response
);
507 memcpy(tmp
, nt_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
508 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
511 tmsg
->sess_len1
= tmsg
->sess_len2
= NTLMSSP_SESSION_KEY_LEN
;
512 tmsg
->sess_off
= tmsg
->nt_resp_off
+ tmsg
->nt_resp_len1
;
514 MD4(response_key_nt
, 16, session_base_key
);
516 KXKEY(session_base_key
, lm_challenge_response
, key_exchange_key
);
518 NONCE (exported_session_key
, 16);
520 *ntlm_key
= g_strndup (exported_session_key
, 16);
522 RC4K (key_exchange_key
, exported_session_key
, encrypted_random_session_key
);
523 memcpy(tmp
, encrypted_random_session_key
, 16);
524 tmp
+= NTLMSSP_SESSION_KEY_LEN
;
526 tmp
= purple_base64_encode((guchar
*) tmsg
, msglen
);
527 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE message\n");