[gtk-vnc-devel] [patch] - MSLogon feature implemented



Hi, folks.

Attached is a patch which implements UltraVNC's MS Logon feature.
Basically it adds another authentication type.

After our talk on IRC, I sent a couple of emails to UltraVNC guys,
asking them to request this auth number to be included in the spec.

In the meantime the patch is here for reviewing. Comments are welcome.

Cheers,
-- 
Jonh Wendell
http://www.bani.com.br
diff -r a3c68b4f30bd src/Makefile.am
--- a/src/Makefile.am	Mon Sep 15 09:16:55 2008 -0300
+++ b/src/Makefile.am	Sat Oct 04 18:20:14 2008 -0300
@@ -22,6 +22,7 @@
 	vncdisplay.h vncdisplay.c \
         vncmarshal.h vncmarshal.c \
 	x_keymap.h x_keymap.c vnc_keycodes.h \
+	dh.h dh.c \
 	utils.h
 
 if WITH_UCONTEXT
diff -r a3c68b4f30bd src/dh.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dh.c	Sat Oct 04 18:20:14 2008 -0300
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008  Jonh Wendell <wendell bani com br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 or
+ * later as published by the Free Software Foundation.
+ *
+ * This is a C implementation, based on a C++ implementation by
+ * Lee Griffiths (lee griffiths first4internet co uk):
+
+ * CRYPTO LIBRARY FOR EXCHANGING KEYS
+ * USING THE DIFFIE-HELLMAN KEY EXCHANGE PROTOCOL
+ * Implemented by Lee Griffiths, Jan 2004.
+ * This software is freeware, you may use it to your discretion,
+ * however by doing so you take full responsibility for any damage
+ * it may cause.
+
+ * The diffie-hellman can be used to securely exchange keys
+ * between parties, where a third party eavesdropper given
+ * the values being transmitted cannot determine the key.
+ *
+ *  GTK VNC Widget
+*/
+
+#include "dh.h"
+#include <stdlib.h>
+
+#define DH_MAX_BITS 31
+
+struct _DhCryptPrivate
+{
+  guint64 gen, mod, key, priv, pub, max_num;
+};
+
+DhCrypt *
+dh_crypt_new (guint64 gen, guint64 mod)
+{
+	DhCrypt *dh;
+
+	dh = g_new0 (DhCrypt, 1);
+	dh->priv = g_new0 (DhCryptPrivate, 1);
+
+	dh->priv->gen = gen;
+	dh->priv->mod = mod;
+	dh->priv->max_num = ((guint64) 1) << DH_MAX_BITS;
+
+	srand((unsigned) time(NULL));
+
+	return dh;
+}
+
+void
+dh_crypt_free (DhCrypt *dh)
+{
+	dh->priv->gen = 0;
+	dh->priv->mod = 0;
+	dh->priv->priv = 0;
+	dh->priv->pub = 0;
+	dh->priv->key = 0;
+
+	g_free (dh->priv);
+	g_free (dh);
+	dh = NULL;
+}
+
+
+static guint64
+rng (guint64 limit)
+{
+	return ((((guint64) rand()) * rand() * rand ()) % limit);
+}
+
+/*
+Raises X to the power Y in modulus N
+the values of X, Y, and N can be massive, and this can be 
+achieved by first calculating X to the power of 2 then 
+using power chaining over modulus N */
+static guint64
+XpowYmodN(guint64 x, guint64 y, guint64 N)
+{
+	guint64 result = 1;
+	const guint64 oneShift63 = ((guint64) 1) << 63;
+	int i;
+	
+	for (i = 0; i < 64; y <<= 1, i++) {
+		result = result * result % N;
+		if (y & oneShift63)
+			result = result * x % N;
+	}
+
+	return result;
+}
+
+guint64
+dh_crypt_gen_inter_key (DhCrypt *dh)
+{
+	dh->priv->priv = rng(dh->priv->max_num);
+	return dh->priv->pub = XpowYmodN(dh->priv->gen,dh->priv->priv,dh->priv->mod);
+}
+
+guint64 dh_crypt_gen_encryption_key (DhCrypt *dh, guint64 inter_key)
+{
+	if (inter_key >= dh->priv->max_num)
+		return 0;
+
+	return dh->priv->key = XpowYmodN(inter_key, dh->priv->priv, dh->priv->mod);
+}
+
+void
+dh_int64ToBytes(const guint64 integer, char* const bytes)
+{
+	int i;
+	for (i = 0; i < 8; i++)
+		bytes[i] = (unsigned char) (integer >> (8 * (7 - i)));
+}
+
+guint64
+dh_bytesToInt64(const char* const bytes)
+{
+	guint64 result = 0;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		result <<= 8;
+		result += (unsigned char) bytes[i];
+	}
+	return result;
+}
diff -r a3c68b4f30bd src/dh.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dh.h	Sat Oct 04 18:20:14 2008 -0300
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008  Jonh Wendell <wendell bani com br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 or
+ * later as published by the Free Software Foundation.
+
+ * This is a C implementation, based on a C++ implementation by
+ * Lee Griffiths (lee griffiths first4internet co uk):
+
+ * CRYPTO LIBRARY FOR EXCHANGING KEYS
+ * USING THE DIFFIE-HELLMAN KEY EXCHANGE PROTOCOL
+ * Implemented by Lee Griffiths, Jan 2004.
+ * This software is freeware, you may use it to your discretion,
+ * however by doing so you take full responsibility for any damage
+ * it may cause.
+
+ * The diffie-hellman can be used to securely exchange keys
+ * between parties, where a third party eavesdropper given
+ * the values being transmitted cannot determine the key.
+ *
+ *  GTK VNC Widget
+*/
+
+#ifndef __DH_H__
+#define __DH_H__
+
+#include <glib.h>
+
+typedef struct _DhCrypt DhCrypt;
+typedef struct _DhCryptPrivate DhCryptPrivate;
+
+struct _DhCrypt {
+  DhCryptPrivate *priv;
+};
+
+DhCrypt *	dh_crypt_new (guint64 gen, guint64 mod);
+guint64		dh_crypt_gen_inter_key (DhCrypt *dh);
+guint64		dh_crypt_gen_encryption_key (DhCrypt *dh, guint64 inter_key);
+
+void		dh_crypt_free (DhCrypt *dh);
+
+void		dh_int64ToBytes(const guint64 integer, char* const bytes);
+guint64		dh_bytesToInt64(const char* const bytes);
+
+#endif // __DH_H__
diff -r a3c68b4f30bd src/gvnc.c
--- a/src/gvnc.c	Mon Sep 15 09:16:55 2008 -0300
+++ b/src/gvnc.c	Sat Oct 04 18:20:14 2008 -0300
@@ -34,6 +34,7 @@
 #include "utils.h"
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
+#include "dh.h"
 
 #include <zlib.h>
 
@@ -2144,6 +2145,58 @@
 	return gvnc_check_auth_result(gvnc);
 }
 
+/*
+ *   marscha 2006 - Martin Scharpf
+ *   Encrypt bytes[length] in memory using key.
+ *   Key has to be 8 bytes, length a multiple of 8 bytes.
+*/
+static void
+vncEncryptBytes2(unsigned char *where, const int length, unsigned char *key) {
+	int i, j;
+	deskey(key, EN0);
+	for (i = 0; i< 8; i++)
+		where[i] ^= key[i];
+	des(where, where);
+	for (i = 8; i < length; i += 8) {
+		for (j = 0; j < 8; j++)
+			where[i + j] ^= where[i + j - 8];
+		des(where + i, where + i);
+	}
+}
+static gboolean gvnc_perform_auth_mslogon(struct gvnc *gvnc)
+{
+	char gen[8], mod[8], resp[8], pub[8], user[256], passwd[64];
+	unsigned char key[8];
+	DhCrypt *dh;
+
+	GVNC_DEBUG("Do Challenge\n");
+	if (!gvnc->cred_username)
+		return FALSE;
+	if (!gvnc->cred_password)
+		return FALSE;
+
+	gvnc_read(gvnc, gen, sizeof(gen));
+	gvnc_read(gvnc, mod, sizeof(mod));
+	gvnc_read(gvnc, resp, sizeof(resp));
+
+	dh = dh_crypt_new (dh_bytesToInt64(gen), dh_bytesToInt64(mod));
+	dh_int64ToBytes (dh_crypt_gen_inter_key (dh), pub);
+	gvnc_write(gvnc, pub, sizeof(pub));
+
+	dh_int64ToBytes(dh_crypt_gen_encryption_key(dh, dh_bytesToInt64(resp)), (char*) key);
+
+	strncpy(passwd, (char*)gvnc->cred_password, sizeof(passwd));
+	strncpy(user, (char*)gvnc->cred_username, sizeof(user));
+	vncEncryptBytes2((unsigned char*) user, sizeof(user), key);
+	vncEncryptBytes2((unsigned char*) passwd, sizeof(passwd), key);
+
+	gvnc_write(gvnc, user, sizeof(user));
+	gvnc_write(gvnc, passwd, sizeof(passwd));
+	gvnc_flush(gvnc);
+
+	dh_crypt_free (dh);
+	return gvnc_check_auth_result(gvnc);
+}
 
 static gboolean gvnc_start_tls(struct gvnc *gvnc, int anonTLS)
 {
@@ -2269,6 +2322,9 @@
                         return TRUE;
         }
 
+        if (gvnc->auth_type == GVNC_AUTH_MSLOGON)
+                return TRUE;
+
         return FALSE;
 }
 
@@ -2280,6 +2336,9 @@
                     gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509PLAIN)
                         return TRUE;
         }
+
+        if (gvnc->auth_type == GVNC_AUTH_MSLOGON)
+                return TRUE;
 
         return FALSE;
 }
@@ -2598,6 +2657,9 @@
 	case GVNC_AUTH_VENCRYPT:
 		return gvnc_perform_auth_vencrypt(gvnc);
 
+	case GVNC_AUTH_MSLOGON:
+		return gvnc_perform_auth_mslogon(gvnc);
+
 	default:
 		if (gvnc->ops.auth_unsupported)
 			gvnc->ops.auth_unsupported (gvnc->ops_data, gvnc->auth_type);
@@ -2940,6 +3002,7 @@
         if (type != GVNC_AUTH_NONE &&
             type != GVNC_AUTH_VNC &&
             type != GVNC_AUTH_TLS &&
+            type != GVNC_AUTH_MSLOGON &&
             type != GVNC_AUTH_VENCRYPT) {
             	if (gvnc->ops.auth_unsupported)
 					gvnc->ops.auth_unsupported (gvnc->ops_data, type);
diff -r a3c68b4f30bd src/gvnc.h
--- a/src/gvnc.h	Mon Sep 15 09:16:55 2008 -0300
+++ b/src/gvnc.h	Sat Oct 04 18:20:15 2008 -0300
@@ -108,7 +108,8 @@
 	GVNC_AUTH_TIGHT = 16,
 	GVNC_AUTH_ULTRA = 17,
 	GVNC_AUTH_TLS = 18,  /* Used by VINO */
-	GVNC_AUTH_VENCRYPT = 19 /* Used by VeNCrypt and QEMU */
+	GVNC_AUTH_VENCRYPT = 19, /* Used by VeNCrypt and QEMU */
+	GVNC_AUTH_MSLOGON = 0xfffffffa /* Used by UltraVNC */
 } gvnc_auth;
 
 typedef enum {
diff -r a3c68b4f30bd src/vncdisplay.c
--- a/src/vncdisplay.c	Mon Sep 15 09:16:55 2008 -0300
+++ b/src/vncdisplay.c	Sat Oct 04 18:20:15 2008 -0300
@@ -1861,6 +1861,7 @@
 
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VENCRYPT));
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_TLS));
+	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_MSLOGON));
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VNC));
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_NONE));
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]