Merged in CMaiku/pidgin (pull request #199)
Split and internalize NTLM code
Approved-by: Gary Kramlich
Approved-by: Eion Robb
Approved-by: dx
--- a/ChangeLog.API Thu Jun 15 03:32:52 2017 +0000
+++ b/ChangeLog.API Thu Jun 15 03:52:01 2017 +0000
@@ -462,6 +462,7 @@
* purple_notify_searchresults_get_columns_count
* purple_notify_searchresults_get_rows_count
* purple_notify_searchresults_row_get
--- a/doc/reference/libpurple/libpurple-docs.xml Thu Jun 15 03:32:52 2017 +0000
+++ b/doc/reference/libpurple/libpurple-docs.xml Thu Jun 15 03:52:01 2017 +0000
@@ -59,7 +59,6 @@
<xi:include href="xml/nat-pmp.xml" />
<xi:include href="xml/network.xml" />
<xi:include href="xml/notify.xml" />
- <xi:include href="xml/ntlm.xml" />
<xi:include href="xml/plugins.xml" />
<xi:include href="xml/prefs.xml" />
<xi:include href="xml/pluginpref.xml" />
--- a/libpurple/Makefile.am Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/Makefile.am Thu Jun 15 03:52:01 2017 +0000
@@ -78,7 +78,6 @@
@@ -163,7 +162,6 @@
--- a/libpurple/Makefile.mingw Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/Makefile.mingw Thu Jun 15 03:52:01 2017 +0000
@@ -102,7 +102,6 @@
--- a/libpurple/http.c Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/http.c Thu Jun 15 03:52:01 2017 +0000
@@ -26,7 +26,6 @@
@@ -230,6 +229,25 @@
+struct _ntlm_type1_message { + guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */ + guint32 type; /* 0x00000001 */ + guint32 flags; /* 0x0000b203 */ + guint16 dom_len1; /* domain string length */ + guint16 dom_len2; /* domain string length */ + guint32 dom_off; /* domain string offset */ + guint16 host_len1; /* host string length */ + guint16 host_len2; /* host string length */ + guint32 host_off; /* host string offset (always 0x00000020) */ + guint8 host[*]; /* host string (ASCII) */ + guint8 dom[*]; /* domain string (ASCII) */ static time_t purple_http_rfc1123_to_time(const gchar *str);
static gboolean purple_http_request_is_method(PurpleHttpRequest *request,
@@ -461,6 +479,56 @@
+/*** NTLM *********************************************************************/ + * purple_ntlm_gen_type1: + * @hostname: Your hostname + * @domain: The domain to authenticate to + * Generates the base64 encoded type 1 message needed for NTLM authentication + * Returns: base64 encoded string to send to the server. This should + * be g_free'd by the caller. +purple_http_ntlm_gen_type1(const gchar *hostname, const gchar *domain) + int hostnamelen,host_off; + struct _ntlm_type1_message *tmsg; + hostnamelen = strlen(hostname); + domainlen = strlen(domain); + host_off = sizeof(struct _ntlm_type1_message); + dom_off = sizeof(struct _ntlm_type1_message) + hostnamelen; + msg = g_malloc0(sizeof(struct _ntlm_type1_message) + hostnamelen + domainlen); + tmsg = (struct _ntlm_type1_message*)(gpointer)msg; + tmsg->protocol[0] = 'N'; + tmsg->protocol[1] = 'T'; + tmsg->protocol[2] = 'L'; + tmsg->protocol[3] = 'M'; + tmsg->protocol[4] = 'S'; + tmsg->protocol[5] = 'S'; + tmsg->protocol[6] = 'P'; + tmsg->protocol[7] = '\0'; + tmsg->type = GUINT32_TO_LE(0x00000001); + tmsg->flags = GUINT32_TO_LE(0x0000b203); + tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen); + tmsg->dom_off = GUINT32_TO_LE(dom_off); + tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen); + tmsg->host_off = GUINT32_TO_LE(host_off); + memcpy(msg + host_off, hostname, hostnamelen); + memcpy(msg + dom_off, domain, domainlen); + tmp = g_base64_encode(msg, sizeof(struct _ntlm_type1_message) + hostnamelen + domainlen); /*** HTTP Sockets *************************************************************/
@@ -863,7 +931,8 @@
- ntlm_type1 = purple_ntlm_gen_type1(purple_get_host_name(), "");
+ ntlm_type1 = purple_http_ntlm_gen_type1(purple_get_host_name(), g_string_append_printf(h, "Proxy-Authorization: Basic %s\r\n",
--- a/libpurple/ntlm.c Thu Jun 15 03:32:52 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,404 +0,0 @@
- * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
- * hashing done according to description of NTLM on
- * http://www.innovation.ch/java/ntlm.html
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#include "ciphers/descipher.h"
-#include "ciphers/md4hash.h"
-#define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
- guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
- guint32 type; /* 0x00000001 */
- guint32 flags; /* 0x0000b203 */
- guint16 dom_len1; /* domain string length */
- guint16 dom_len2; /* domain string length */
- guint32 dom_off; /* domain string offset */
- guint16 host_len1; /* host string length */
- guint16 host_len2; /* host string length */
- guint32 host_off; /* host string offset (always 0x00000020) */
- guint8 host[*]; /* host string (ASCII) */
- guint8 dom[*]; /* domain string (ASCII) */
- guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
- guint32 type; /* 0x00000002 */
- guint16 msg_len1; /* target name length */
- guint16 msg_len2; /* target name length */
- guint32 flags; /* 0x00008201 */
- guint8 nonce[8]; /* nonce */
- guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
- guint32 type; /* 0x00000003 */
- guint16 lm_resp_len1; /* LanManager response length (always 0x18)*/
- guint16 lm_resp_len2; /* LanManager response length (always 0x18)*/
- guint32 lm_resp_off; /* LanManager response offset */
- guint16 nt_resp_len1; /* NT response length (always 0x18) */
- guint16 nt_resp_len2; /* NT response length (always 0x18) */
- guint32 nt_resp_off; /* NT response offset */
- guint16 dom_len1; /* domain string length */
- guint16 dom_len2; /* domain string length */
- guint32 dom_off; /* domain string offset (always 0x00000040) */
- guint16 user_len1; /* username string length */
- guint16 user_len2; /* username string length */
- guint32 user_off; /* username string offset */
- guint16 host_len1; /* host string length */
- guint16 host_len2; /* host string length */
- guint32 host_off; /* host string offset */
- guint32 sess_off; /* message length */
- guint32 flags; /* 0x00008201 */
- /* guint32 flags2; */ /* unknown, used in windows messenger */
- guint8 dom[*]; /* domain string (unicode UTF-16LE) */
- guint8 user[*]; /* username string (unicode UTF-16LE) */
- guint8 host[*]; /* host string (unicode UTF-16LE) */
- guint8 lm_resp[*]; /* LanManager response */
- guint8 nt_resp[*]; /* NT response */
-purple_ntlm_gen_type1(const gchar *hostname, const gchar *domain)
- int hostnamelen,host_off;
- struct type1_message *tmsg;
- hostnamelen = strlen(hostname);
- domainlen = strlen(domain);
- host_off = sizeof(struct type1_message);
- dom_off = sizeof(struct type1_message) + hostnamelen;
- msg = g_malloc0(sizeof(struct type1_message) + hostnamelen + domainlen);
- tmsg = (struct type1_message*)(gpointer)msg;
- tmsg->protocol[0] = 'N';
- tmsg->protocol[1] = 'T';
- tmsg->protocol[2] = 'L';
- tmsg->protocol[3] = 'M';
- tmsg->protocol[4] = 'S';
- tmsg->protocol[5] = 'S';
- tmsg->protocol[6] = 'P';
- tmsg->protocol[7] = '\0';
- tmsg->type = GUINT32_TO_LE(0x00000001);
- tmsg->flags = GUINT32_TO_LE(0x0000b203);
- tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen);
- tmsg->dom_off = GUINT32_TO_LE(dom_off);
- tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen);
- tmsg->host_off = GUINT32_TO_LE(host_off);
- memcpy(msg + host_off, hostname, hostnamelen);
- memcpy(msg + dom_off, domain, domainlen);
- tmp = g_base64_encode(msg, sizeof(struct type1_message) + hostnamelen + domainlen);
-purple_ntlm_parse_type2(const gchar *type2, guint32 *flags)
- struct type2_message tmsg;
- static guint8 nonce[8];
- buff = g_base64_decode(type2, &retlen);
- if (buff != NULL && retlen >= (sizeof(struct type2_message) - 1)) {
- memcpy(&tmsg, buff, MIN(retlen, sizeof(tmsg)));
- memcpy(nonce, tmsg.nonce, 8);
- *flags = GUINT16_FROM_LE(tmsg.flags);
- purple_debug_error("ntlm", "Unable to parse type2 message - returning empty nonce.\n");
- * Create a 64bit DES key by taking a 56bit key and adding
- * a parity bit after every 7th bit.
-setup_des_key(const guint8 key_56[], guint8 *key)
- key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
- key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
- key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
- key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
- key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
- key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
- key[7] = (key_56[6] << 1) & 0xFF;
- * helper function for purple cipher.c
-des_ecb_encrypt(const guint8 *plaintext, guint8 *result, const guint8 *key)
- cipher = purple_des_cipher_new();
- purple_cipher_set_key(cipher, key, 8);
- encsiz = purple_cipher_encrypt(cipher, plaintext, 8, result, 8);
- g_warn_if_fail(encsiz == 8);
- g_object_unref(cipher);
- * takes a 21 byte array and treats it as 3 56-bit DES keys. The
- * 8 byte plaintext is encrypted with each key and the resulting 24
- * bytes are stored in the results array.
-calc_resp(guint8 *keys, const guint8 *plaintext, unsigned char *results)
- setup_des_key(keys, key);
- des_ecb_encrypt(plaintext, results, key);
- setup_des_key(keys + 7, key);
- des_ecb_encrypt(plaintext, results + 8, key);
- setup_des_key(keys + 14, key);
- des_ecb_encrypt(plaintext, results + 16, key);
- * TODO: We think we should be using cryptographically secure random numbers
- * here. We think the rand() function is probably bad. We think
- * /dev/urandom is a step up, but using a random function from an SSL
- * library would probably be best. In Windows we could possibly also
-gensesskey(char *buffer)
- fd = open("/dev/urandom", O_RDONLY);
- red = read(fd, buffer, 16);
- purple_debug_warning("ntlm", "Error reading from /dev/urandom: %s."
- " Falling back to inferior method.\n", g_strerror(errno));
- purple_debug_warning("ntlm", "Tried reading 16 bytes from "
- "/dev/urandom but only got %"
- G_GSSIZE_FORMAT ". Falling back to "
- "inferior method\n", (gssize)red);
- purple_debug_warning("ntlm", "Error opening /dev/urandom: %s."
- " Falling back to inferior method.\n", g_strerror(errno));
- for (i = red; i < 16; i++) {
- buffer[i] = (char)(g_random_int() & 0xff);
-purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags)
- unsigned char lm_hpw[21];
- struct type3_message *tmsg;
- unsigned char lm_resp[24], nt_resp[24];
- unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
- unsigned char nt_hpw[21];
- domainlen = strlen(domain) * 2;
- usernamelen = strlen(username) * 2;
- hostnamelen = strlen(hostname) * 2;
- msglen = sizeof(struct type3_message) + domainlen +
- usernamelen + hostnamelen + 0x18 + 0x18 + ((flags) ? 0x10 : 0);
- tmsg = g_malloc0(msglen);
- passwlen = strlen(passw);
- /* type3 message initialization */
- tmsg->protocol[0] = 'N';
- tmsg->protocol[1] = 'T';
- tmsg->protocol[2] = 'L';
- tmsg->protocol[3] = 'M';
- tmsg->protocol[4] = 'S';
- tmsg->protocol[5] = 'S';
- tmsg->protocol[6] = 'P';
- tmsg->type = GUINT32_TO_LE(0x00000003);
- tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = GUINT16_TO_LE(0x18);
- tmsg->lm_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen);
- tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = GUINT16_TO_LE(0x18);
- tmsg->nt_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18);
- tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen);
- tmsg->dom_off = GUINT32_TO_LE(sizeof(struct type3_message));
- tmsg->user_len1 = tmsg->user_len2 = GUINT16_TO_LE(usernamelen);
- tmsg->user_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen);
- tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen);
- tmsg->host_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen);
- tmsg->sess_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18 + 0x18);
- tmsg->sess_len1 = tmsg->sess_len2 = GUINT16_TO_LE(0x0010);
- tmsg->flags = GUINT32_TO_LE(0x00008201);
- tmp = (char *)tmsg + sizeof(struct type3_message);
- ucs2le = g_convert(domain, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
- memcpy(tmp, ucs2le, domainlen);
- purple_debug_info("ntlm", "Unable to encode domain in UTF-16LE.\n");
- ucs2le = g_convert(username, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
- memcpy(tmp, ucs2le, usernamelen);
- purple_debug_info("ntlm", "Unable to encode username in UTF-16LE.\n");
- ucs2le = g_convert(hostname, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL);
- memcpy(tmp, ucs2le, hostnamelen);
- purple_debug_info("ntlm", "Unable to encode hostname in UTF-16LE.\n");
- for (idx = 0; idx < passwlen; idx++)
- lm_pw[idx] = g_ascii_toupper(passw[idx]);
- for (; idx < 14; idx++)
- setup_des_key((unsigned char*)lm_pw, key);
- des_ecb_encrypt(magic, lm_hpw, key);
- setup_des_key((unsigned char*)(lm_pw + 7), key);
- des_ecb_encrypt(magic, lm_hpw + 8, key);
- memset(lm_hpw + 16, 0, 5);
- calc_resp(lm_hpw, nonce, lm_resp);
- memcpy(tmp, lm_resp, 0x18);
- /* Convert the password to UTF-16LE */
- for (idx = 0; idx < lennt; idx++)
- nt_pw[2 * idx] = passw[idx];
- nt_pw[2 * idx + 1] = 0;
- hash = purple_md4_hash_new();
- purple_hash_append(hash, (guint8 *)nt_pw, 2 * lennt);
- purple_hash_digest(hash, nt_hpw, sizeof(nt_hpw));
- memset(nt_hpw + 16, 0, 5);
- calc_resp(nt_hpw, nonce, nt_resp);
- memcpy(tmp, nt_resp, 0x18);
- tmsg->flags = GUINT32_TO_LE(0x409082d4);
- memcpy(tmp, sesskey, 0x10);
- /*tmsg->flags2 = 0x0a280105;
- tmsg->flags3 = 0x0f000000;*/
- tmp = g_base64_encode((guchar *)tmsg, msglen);
--- a/libpurple/ntlm.h Thu Jun 15 03:32:52 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
- * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
- * ntlm structs are taken from NTLM description on
- * http://www.innovation.ch/java/ntlm.html
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- * @section_id: libpurple-ntlm
- * @short_description: <filename>ntlm.h</filename>
- * @title: NTLM Authentication
- * purple_ntlm_gen_type1:
- * @hostname: Your hostname
- * @domain: The domain to authenticate to
- * Generates the base64 encoded type 1 message needed for NTLM authentication
- * Returns: base64 encoded string to send to the server. This should
- * be g_free'd by the caller.
-gchar *purple_ntlm_gen_type1(const gchar *hostname, const gchar *domain);
- * purple_ntlm_parse_type2:
- * @type2: String containing the base64 encoded type2 message
- * @flags: If not %NULL, this will store the flags for the message
- * Parses the ntlm type 2 message
- * Returns: The nonce for use in message type3. This is a statically
- * allocated 8 byte binary string.
-guint8 *purple_ntlm_parse_type2(const gchar *type2, guint32 *flags);
- * purple_ntlm_gen_type3:
- * @username: The username
- * @hostname: The hostname
- * @domain: The domain to authenticate against
- * @nonce: The nonce returned by purple_ntlm_parse_type2
- * @flags: Pointer to the flags returned by purple_ntlm_parse_type2
- * Generates a type3 message
- * Returns: A base64 encoded type3 message. This should be g_free'd by
-gchar *purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags);
-#endif /* _PURPLE_NTLM_H */
--- a/libpurple/protocols/simple/Makefile.am Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/protocols/simple/Makefile.am Thu Jun 15 03:52:01 2017 +0000
@@ -4,6 +4,8 @@
pkgdir = @PURPLE_PLUGINDIR@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/simple/ntlm.c Thu Jun 15 03:52:01 2017 +0000
@@ -0,0 +1,347 @@
+ * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de> + * hashing done according to description of NTLM on + * http://www.innovation.ch/java/ntlm.html + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +#include "ciphers/descipher.h" +#include "ciphers/md4hash.h" +#define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000 + guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ + guint32 type; /* 0x00000002 */ + guint16 msg_len1; /* target name length */ + guint16 msg_len2; /* target name length */ + guint32 flags; /* 0x00008201 */ + guint8 nonce[8]; /* nonce */ + guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ + guint32 type; /* 0x00000003 */ + guint16 lm_resp_len1; /* LanManager response length (always 0x18)*/ + guint16 lm_resp_len2; /* LanManager response length (always 0x18)*/ + guint32 lm_resp_off; /* LanManager response offset */ + guint16 nt_resp_len1; /* NT response length (always 0x18) */ + guint16 nt_resp_len2; /* NT response length (always 0x18) */ + guint32 nt_resp_off; /* NT response offset */ + guint16 dom_len1; /* domain string length */ + guint16 dom_len2; /* domain string length */ + guint32 dom_off; /* domain string offset (always 0x00000040) */ + guint16 user_len1; /* username string length */ + guint16 user_len2; /* username string length */ + guint32 user_off; /* username string offset */ + guint16 host_len1; /* host string length */ + guint16 host_len2; /* host string length */ + guint32 host_off; /* host string offset */ + guint32 sess_off; /* message length */ + guint32 flags; /* 0x00008201 */ + /* guint32 flags2; */ /* unknown, used in windows messenger */ + guint8 dom[*]; /* domain string (unicode UTF-16LE) */ + guint8 user[*]; /* username string (unicode UTF-16LE) */ + guint8 host[*]; /* host string (unicode UTF-16LE) */ + guint8 lm_resp[*]; /* LanManager response */ + guint8 nt_resp[*]; /* NT response */ +purple_ntlm_parse_type2(const gchar *type2, guint32 *flags) + struct type2_message tmsg; + static guint8 nonce[8]; + buff = g_base64_decode(type2, &retlen); + if (buff != NULL && retlen >= (sizeof(struct type2_message) - 1)) { + memcpy(&tmsg, buff, MIN(retlen, sizeof(tmsg))); + memcpy(nonce, tmsg.nonce, 8); + *flags = GUINT16_FROM_LE(tmsg.flags); + purple_debug_error("ntlm", "Unable to parse type2 message - returning empty nonce.\n"); + * Create a 64bit DES key by taking a 56bit key and adding + * a parity bit after every 7th bit. +setup_des_key(const guint8 key_56[], guint8 *key) + key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1); + key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2); + key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3); + key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4); + key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5); + key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6); + key[7] = (key_56[6] << 1) & 0xFF; + * helper function for purple cipher.c +des_ecb_encrypt(const guint8 *plaintext, guint8 *result, const guint8 *key) + cipher = purple_des_cipher_new(); + purple_cipher_set_key(cipher, key, 8); + encsiz = purple_cipher_encrypt(cipher, plaintext, 8, result, 8); + g_warn_if_fail(encsiz == 8); + g_object_unref(cipher); + * takes a 21 byte array and treats it as 3 56-bit DES keys. The + * 8 byte plaintext is encrypted with each key and the resulting 24 + * bytes are stored in the results array. +calc_resp(guint8 *keys, const guint8 *plaintext, unsigned char *results) + setup_des_key(keys, key); + des_ecb_encrypt(plaintext, results, key); + setup_des_key(keys + 7, key); + des_ecb_encrypt(plaintext, results + 8, key); + setup_des_key(keys + 14, key); + des_ecb_encrypt(plaintext, results + 16, key); + * TODO: We think we should be using cryptographically secure random numbers + * here. We think the rand() function is probably bad. We think + * /dev/urandom is a step up, but using a random function from an SSL + * library would probably be best. In Windows we could possibly also +gensesskey(char *buffer) + fd = open("/dev/urandom", O_RDONLY); + red = read(fd, buffer, 16); + purple_debug_warning("ntlm", "Error reading from /dev/urandom: %s." + " Falling back to inferior method.\n", g_strerror(errno)); + purple_debug_warning("ntlm", "Tried reading 16 bytes from " + "/dev/urandom but only got %" + G_GSSIZE_FORMAT ". Falling back to " + "inferior method\n", (gssize)red); + purple_debug_warning("ntlm", "Error opening /dev/urandom: %s." + " Falling back to inferior method.\n", g_strerror(errno)); + for (i = red; i < 16; i++) { + buffer[i] = (char)(g_random_int() & 0xff); +purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags) + unsigned char lm_hpw[21]; + struct type3_message *tmsg; + unsigned char lm_resp[24], nt_resp[24]; + unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; + unsigned char nt_hpw[21]; + domainlen = strlen(domain) * 2; + usernamelen = strlen(username) * 2; + hostnamelen = strlen(hostname) * 2; + msglen = sizeof(struct type3_message) + domainlen + + usernamelen + hostnamelen + 0x18 + 0x18 + ((flags) ? 0x10 : 0); + tmsg = g_malloc0(msglen); + passwlen = strlen(passw); + /* type3 message initialization */ + tmsg->protocol[0] = 'N'; + tmsg->protocol[1] = 'T'; + tmsg->protocol[2] = 'L'; + tmsg->protocol[3] = 'M'; + tmsg->protocol[4] = 'S'; + tmsg->protocol[5] = 'S'; + tmsg->protocol[6] = 'P'; + tmsg->type = GUINT32_TO_LE(0x00000003); + tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = GUINT16_TO_LE(0x18); + tmsg->lm_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen); + tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = GUINT16_TO_LE(0x18); + tmsg->nt_resp_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18); + tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen); + tmsg->dom_off = GUINT32_TO_LE(sizeof(struct type3_message)); + tmsg->user_len1 = tmsg->user_len2 = GUINT16_TO_LE(usernamelen); + tmsg->user_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen); + tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen); + tmsg->host_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen); + tmsg->sess_off = GUINT32_TO_LE(sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18 + 0x18); + tmsg->sess_len1 = tmsg->sess_len2 = GUINT16_TO_LE(0x0010); + tmsg->flags = GUINT32_TO_LE(0x00008201); + tmp = (char *)tmsg + sizeof(struct type3_message); + ucs2le = g_convert(domain, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL); + memcpy(tmp, ucs2le, domainlen); + purple_debug_info("ntlm", "Unable to encode domain in UTF-16LE.\n"); + ucs2le = g_convert(username, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL); + memcpy(tmp, ucs2le, usernamelen); + purple_debug_info("ntlm", "Unable to encode username in UTF-16LE.\n"); + ucs2le = g_convert(hostname, -1, "UTF-16LE", "UTF-8", NULL, NULL, NULL); + memcpy(tmp, ucs2le, hostnamelen); + purple_debug_info("ntlm", "Unable to encode hostname in UTF-16LE.\n"); + for (idx = 0; idx < passwlen; idx++) + lm_pw[idx] = g_ascii_toupper(passw[idx]); + for (; idx < 14; idx++) + setup_des_key((unsigned char*)lm_pw, key); + des_ecb_encrypt(magic, lm_hpw, key); + setup_des_key((unsigned char*)(lm_pw + 7), key); + des_ecb_encrypt(magic, lm_hpw + 8, key); + memset(lm_hpw + 16, 0, 5); + calc_resp(lm_hpw, nonce, lm_resp); + memcpy(tmp, lm_resp, 0x18); + /* Convert the password to UTF-16LE */ + for (idx = 0; idx < lennt; idx++) + nt_pw[2 * idx] = passw[idx]; + nt_pw[2 * idx + 1] = 0; + hash = purple_md4_hash_new(); + purple_hash_append(hash, (guint8 *)nt_pw, 2 * lennt); + purple_hash_digest(hash, nt_hpw, sizeof(nt_hpw)); + memset(nt_hpw + 16, 0, 5); + calc_resp(nt_hpw, nonce, nt_resp); + memcpy(tmp, nt_resp, 0x18); + tmsg->flags = GUINT32_TO_LE(0x409082d4); + memcpy(tmp, sesskey, 0x10); + /*tmsg->flags2 = 0x0a280105; + tmsg->flags3 = 0x0f000000;*/ + tmp = g_base64_encode((guchar *)tmsg, msglen); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/simple/ntlm.h Thu Jun 15 03:52:01 2017 +0000
@@ -0,0 +1,58 @@
+ * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de> + * ntlm structs are taken from NTLM description on + * http://www.innovation.ch/java/ntlm.html + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + * purple_ntlm_parse_type2: + * @type2: String containing the base64 encoded type2 message + * @flags: If not %NULL, this will store the flags for the message + * Parses the ntlm type 2 message + * Returns: The nonce for use in message type3. This is a statically + * allocated 8 byte binary string. +guint8 *purple_ntlm_parse_type2(const gchar *type2, guint32 *flags); + * purple_ntlm_gen_type3: + * @username: The username + * @hostname: The hostname + * @domain: The domain to authenticate against + * @nonce: The nonce returned by purple_ntlm_parse_type2 + * @flags: Pointer to the flags returned by purple_ntlm_parse_type2 + * Generates a type3 message + * Returns: A base64 encoded type3 message. This should be g_free'd by +gchar *purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags); +#endif /* _PURPLE_NTLM_H */ --- a/libpurple/proxy.c Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/proxy.c Thu Jun 15 03:52:01 2017 +0000
@@ -30,7 +30,6 @@
--- a/libpurple/purple.h.in Thu Jun 15 03:32:52 2017 +0000
+++ b/libpurple/purple.h.in Thu Jun 15 03:52:01 2017 +0000
@@ -70,7 +70,6 @@