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 */
63 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
65 struct challenge_message
{
66 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
67 guint8 type
; /* 0x02 */
69 short msg_len
; /* 0x28 */
71 guint32 flags
; /* 0x8201 */
77 struct authenticate_message
{
78 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
79 //guint32 type; /* 0x03 */
80 guint8 type
; /* 0x03 */
83 guint16 lm_resp_len1
; /* LanManager response length (always 0x18)*/
84 guint16 lm_resp_len2
; /* LanManager response length (always 0x18)*/
85 //guint32 lm_resp_off; /* LanManager response offset */
86 guint16 lm_resp_off
; /* LanManager response offset */
89 /* NtChallengeResponseFields */
90 guint16 nt_resp_len1
; /* NT response length (always 0x18) */
91 guint16 nt_resp_len2
; /* NT response length (always 0x18) */
92 //guint32 nt_resp_off; /* NT response offset */
93 guint16 nt_resp_off
; /* NT response offset */
96 /* DomainNameFields */
97 guint16 dom_len1
; /* domain string length */
98 guint16 dom_len2
; /* domain string length */
99 //guint32 dom_off; /* domain string offset (always 0x40) */
100 guint16 dom_off
; /* domain string offset (always 0x40) */
104 guint16 user_len1
; /* username string length */
105 guint16 user_len2
; /* username string length */
106 //guint32 user_off; /* username string offset */
107 guint16 user_off
; /* username string offset */
110 /* WorkstationFields */
111 guint16 host_len1
; /* host string length */
112 guint16 host_len2
; /* host string length */
113 //guint32 host_off; /* host string offset */
114 guint16 host_off
; /* host string offset */
117 /* EncryptedRandomSessionKeyFields */
131 /* guint32 flags2; unknown, used in windows messenger
135 guint8 dom
[*]; /* domain string (unicode UTF-16LE) */
136 guint8 user
[*]; /* username string (unicode UTF-16LE) */
137 guint8 host
[*]; /* host string (unicode UTF-16LE) */
138 guint8 lm_resp
[*]; /* LanManager response */
139 guint8 nt_resp
[*]; /* NT response */
143 /* Private Methods */
145 static void setup_des_key(const unsigned char key_56
[], char *key
)
148 key
[1] = ((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1);
149 key
[2] = ((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2);
150 key
[3] = ((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3);
151 key
[4] = ((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4);
152 key
[5] = ((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5);
153 key
[6] = ((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6);
154 key
[7] = (key_56
[6] << 1) & 0xFF;
157 static void des_ecb_encrypt(const char *plaintext
, char *result
, const char *key
)
159 PurpleCipher
*cipher
;
160 PurpleCipherContext
*context
;
163 cipher
= purple_ciphers_find_cipher("des");
164 context
= purple_cipher_context_new(cipher
, NULL
);
165 purple_cipher_context_set_key(context
, (guchar
*)key
);
166 purple_cipher_context_encrypt(context
, (guchar
*)plaintext
, 8, (guchar
*)result
, &outlen
);
167 purple_cipher_context_destroy(context
);
171 unicode_strconvcopy(char *dest
, const char *source
, int remlen
)
174 char *inbuf
= (char *) source
;
176 size_t inbytes
= strlen(source
);
177 size_t outbytes
= remlen
;
178 #ifdef HAVE_LANGINFO_CODESET
179 char *sys_cp
= nl_langinfo(CODESET
);
181 char *sys_cp
= SIPE_DEFAULT_CODESET
;
182 #endif /* HAVE_LANGINFO_CODESET */
184 /* fall back to utf-8 */
185 if (!sys_cp
) sys_cp
= "UTF8";
187 fd
= iconv_open("UTF16LE", sys_cp
);
188 iconv(fd
, &inbuf
, &inbytes
, &outbuf
, &outbytes
);
190 return (remlen
- outbytes
);
193 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
195 DES (const char *k
, const char *d
, char * results
)
198 setup_des_key(k
, key
);
199 des_ecb_encrypt(d
, results
, key
);
202 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
204 DESL (char *k
, const char *d
, char * results
)
208 // Copy the first 16 bytes
211 // Zero out the last 5 bytes of the key
212 memset(keys
+ 16, 0, 5);
214 DES(keys
, d
, results
);
215 DES(keys
+ 7, d
, results
+ 8);
216 DES(keys
+ 14, d
, results
+ 16);
220 MD4 (const char * d
, int len
, char * result
)
222 PurpleCipher
* cipher
= purple_ciphers_find_cipher("md4");
223 PurpleCipherContext
* context
= purple_cipher_context_new(cipher
, NULL
);
224 purple_cipher_context_append(context
, (guchar
*)d
, len
);
225 purple_cipher_context_digest(context
, MD4_DIGEST_LEN
, (guchar
*)result
, NULL
);
226 purple_cipher_context_destroy(context
);
231 NTOWFv1 (const char* password
, const char *user
, const char *domain
, char * result
)
233 int len
= 2 * strlen(password
); // utf16 should not be more
234 char *unicode_password
= g_new0(char, len
);
236 len
= unicode_strconvcopy(unicode_password
, password
, len
);
237 MD4 (unicode_password
, len
, result
);
238 g_free(unicode_password
);
242 MD5 (const char * d
, int len
, char * result
)
244 PurpleCipher
* cipher
= purple_ciphers_find_cipher("md5");
245 PurpleCipherContext
* context
= purple_cipher_context_new(cipher
, NULL
);
246 purple_cipher_context_append(context
, (guchar
*)d
, len
);
247 purple_cipher_context_digest(context
, len
, (guchar
*)result
, NULL
);
248 purple_cipher_context_destroy(context
);
252 RC4K (const char * k
, const char * d
, char * result
)
254 PurpleCipherContext
* context
= purple_cipher_context_new_by_name("rc4", NULL
);
255 purple_cipher_context_set_option(context
, "key_len", (gpointer
)16);
256 purple_cipher_context_set_key(context
, k
);
257 purple_cipher_context_encrypt(context
, (const guchar
*)d
, 16, result
, NULL
);
258 purple_cipher_context_destroy(context
);
262 KXKEY (const char * session_base_key
, const char * lm_challenge_resonse
, char * key_exchange_key
)
264 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
265 memcpy(key_exchange_key
, session_base_key
, 16);
268 // This method is only used for NTLM v2 session security w/ enhanced security negotiated
270 SIGNKEY (const char * random_session_key, gboolean client, char * result)
272 char * magic = client
273 ? "session key to client-to-server signing key magic constant"
274 : "session key to server-to-client signing key magic constant";
276 int len = strlen(magic);
277 char md5_input [16 + len];
278 memcpy(md5_input, random_session_key, 16);
279 memcpy(md5_input + 16, magic, len);
281 MD5 (md5_input, len + 16, result);
285 LMOWFv1 (const char *password
, const char *user
, const char *domain
, char *result
)
288 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
289 char uppercase_password
[14];
291 int len
= strlen(password
);
296 // Uppercase password
298 for (i
= 0; i
< len
; i
++) {
299 uppercase_password
[i
] = g_ascii_toupper(password
[i
]);
303 for (; i
< 14; i
++) {
304 uppercase_password
[i
] = 0;
307 DES (uppercase_password
, magic
, result
);
308 DES (uppercase_password
+ 7, magic
, result
+ 8);
312 NONCE(char *buffer
, int num
)
315 for (i
= 0; i
< num
; i
++) {
316 buffer
[i
] = (char)(rand() & 0xff);
320 /* End Private Methods */
322 gchar
*purple_ntlm_parse_challenge(gchar
*challenge
, guint32
*flags
) {
324 static gchar nonce
[8];
325 struct challenge_message
*tmsg
= (struct challenge_message
*)purple_base64_decode((char*)challenge
, &retlen
);
326 memcpy(nonce
, tmsg
->nonce
, 8);
328 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", tmsg
->flags
, tmsg
->flags
& NEGOTIATE_FLAGS
== NEGOTIATE_FLAGS
);
331 *flags
= tmsg
->flags
;
338 print_hex_array(char * msg
, int num
)
341 for (k
= 0; k
< num
; k
++) {
342 printf("0x%02X, ", msg
[k
]&0xff);
348 print_hex_array_title(char * title
, char * msg
, int num
)
350 printf("%s:\n", title
);
351 print_hex_array(msg
, num
);
357 long crc
= crc32(0L, Z_NULL
, 0);
358 crc
= crc32(crc
, msg
, strlen(msg
));
359 char * ptr
= (char*) &crc
;
360 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
365 purple_ntlm_gen_signature (char * buf
, char * signing_key
, guint32 random_pad
, long sequence
, int key_len
)
367 gint32 plaintext
[] = {0, CRC32(buf
), sequence
};
370 PurpleCipherContext
*rc4
= purple_cipher_context_new_by_name("rc4", NULL
);
371 purple_cipher_context_set_option(rc4
, "key_len", (gpointer
)key_len
);
372 purple_cipher_context_set_key(rc4
, signing_key
);
373 purple_cipher_context_encrypt(rc4
, (const guchar
*)plaintext
, 12, result
+4, NULL
);
374 purple_cipher_context_destroy(rc4
);
376 gint32
* res_ptr
= (gint32
*)result
;
377 // Highest four bytes are the Version
378 res_ptr
[0] = 0x00000001;
380 // Replace the first four bytes of the ciphertext with a counter value
381 // currently set to this hardcoded value
382 res_ptr
[1] = random_pad
;
384 gchar signature
[32];
386 for (i
= 0, j
= 0; i
< 16; i
++, j
+=2) {
387 g_sprintf(&signature
[j
], "%02X", result
[i
]);
390 //printf("sig: %s\n", signature);
391 return g_strdup(signature
);
395 purple_ntlm_sipe_signature_make (char * msg
, char * signing_key
)
397 return purple_ntlm_gen_signature(msg
, signing_key
, 0, 100, 16);
401 purple_ntlm_verify_signature (char * a
, char * b
)
403 // Make sure the last 16 bytes match
404 gboolean ret
= strncmp(a
+ 16, b
+ 16, 16) == 0;
409 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
)
411 int msglen
= sizeof(struct authenticate_message
) + 2*(strlen(domain
)
412 + strlen(user
)+ strlen(hostname
) + NTLMSSP_NT_OR_LM_KEY_LEN
)
413 + NTLMSSP_SESSION_KEY_LEN
;
414 struct authenticate_message
*tmsg
= g_malloc0(msglen
);
418 /* authenticate message initialization */
419 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
422 /* Set Negotiate Flags */
423 tmsg
->flags
= NEGOTIATE_FLAGS
;
426 tmsg
->dom_off
= sizeof(struct authenticate_message
);
427 tmp
= ((char*) tmsg
) + tmsg
->dom_off
;
428 remlen
= ((char *)tmsg
)+msglen
-tmp
;
429 tmsg
->dom_len1
= tmsg
->dom_len2
= unicode_strconvcopy(tmp
, domain
, remlen
);
430 tmp
+= tmsg
->dom_len1
;
431 remlen
= ((char *)tmsg
)+msglen
-tmp
;
434 tmsg
->user_off
= tmsg
->dom_off
+ tmsg
->dom_len1
;
435 tmsg
->user_len1
= tmsg
->user_len2
= unicode_strconvcopy(tmp
, user
, remlen
);
436 tmp
+= tmsg
->user_len1
;
437 remlen
= ((char *)tmsg
)+msglen
-tmp
;
440 tmsg
->host_off
= tmsg
->user_off
+ tmsg
->user_len1
;
441 tmsg
->host_len1
= tmsg
->host_len2
= unicode_strconvcopy(tmp
, hostname
, remlen
);
442 tmp
+= tmsg
->host_len1
;
445 tmsg
->lm_resp_len1
= tmsg
->lm_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
446 tmsg
->lm_resp_off
= tmsg
->host_off
+ tmsg
->host_len1
;
448 char response_key_lm
[16];
449 LMOWFv1 (password
, user
, domain
, response_key_lm
);
450 char lm_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
451 DESL (response_key_lm
, nonce
, lm_challenge_response
);
452 memcpy(tmp
, lm_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
453 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
456 tmsg
->nt_resp_len1
= tmsg
->nt_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
457 tmsg
->nt_resp_off
= tmsg
->lm_resp_off
+ tmsg
->lm_resp_len1
;
459 char response_key_nt
[16];
460 NTOWFv1 (password
, user
, domain
, response_key_nt
);
461 char nt_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
462 DESL (response_key_nt
, nonce
, nt_challenge_response
);
463 memcpy(tmp
, nt_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
464 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
467 tmsg
->sess_len1
= tmsg
->sess_len2
= NTLMSSP_SESSION_KEY_LEN
;
468 tmsg
->sess_off
= tmsg
->nt_resp_off
+ tmsg
->nt_resp_len1
;
470 char session_base_key
[16];
471 MD4(response_key_nt
, 16, session_base_key
);
473 char key_exchange_key
[16];
474 KXKEY(session_base_key
, lm_challenge_response
, key_exchange_key
);
476 char exported_session_key
[16];
477 NONCE (exported_session_key
, 16);
479 *ntlm_key
= g_strndup (exported_session_key
, 16);
481 char encrypted_random_session_key
[16];
482 RC4K (key_exchange_key
, exported_session_key
, encrypted_random_session_key
);
483 memcpy(tmp
, encrypted_random_session_key
, 16);
484 tmp
+= NTLMSSP_SESSION_KEY_LEN
;
486 tmp
= purple_base64_encode((guchar
*) tmsg
, msglen
);
487 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE message\n");