diff --git a/lib/handshake.c b/lib/handshake.c
index 206156c1..4c6ef58b 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -70,6 +70,309 @@ interpret_key(const char *key, unsigned long *result)
 	return 0;
 }
 
+
+static int
+handshake_76(struct libwebsocket *wsi)
+{
+	unsigned long key1, key2;
+	unsigned char sum[16];
+	char *response;
+	char *p;
+	int n;
+
+	/* Websocket 76? - confirm we have all the necessary pieces */
+
+	if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
+		!wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
+		!wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
+		!wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
+			     !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
+		/* completed header processing, but missing some bits */
+		goto bail;
+
+	/* allocate the per-connection user memory (if any) */
+
+	if (wsi->protocol->per_session_data_size) {
+		wsi->user_space = malloc(
+				  wsi->protocol->per_session_data_size);
+		if (wsi->user_space  == NULL) {
+			fprintf(stderr, "Out of memory for "
+						   "conn user space\n");
+			goto bail;
+		}
+	} else
+		wsi->user_space = NULL;
+
+	/* create the response packet */
+
+	/* make a buffer big enough for everything */
+
+	response = malloc(256 +
+		wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
+		wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
+		wsi->utf8_token[WSI_TOKEN_HOST].token_len +
+		wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
+		wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
+		wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
+	if (!response) {
+		fprintf(stderr, "Out of memory for response buffer\n");
+		goto bail;
+	}
+
+	p = response;
+	strcpy(p,   "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
+					  "Upgrade: WebSocket\x0d\x0a");
+	p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
+					  "Upgrade: WebSocket\x0d\x0a");
+	strcpy(p,   "Connection: Upgrade\x0d\x0a"
+		    "Sec-WebSocket-Origin: ");
+	p += strlen("Connection: Upgrade\x0d\x0a"
+		    "Sec-WebSocket-Origin: ");
+	strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
+	p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
+#ifdef LWS_OPENSSL_SUPPORT
+	if (use_ssl) {
+		strcpy(p,   "\x0d\x0aSec-WebSocket-Location: wss://");
+		p += strlen("\x0d\x0aSec-WebSocket-Location: wss://");
+	} else {
+#endif
+		strcpy(p,   "\x0d\x0aSec-WebSocket-Location: ws://");
+		p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
+#ifdef LWS_OPENSSL_SUPPORT
+	}
+#endif
+	strcpy(p, wsi->utf8_token[WSI_TOKEN_HOST].token);
+	p += wsi->utf8_token[WSI_TOKEN_HOST].token_len;
+	strcpy(p, wsi->utf8_token[WSI_TOKEN_GET_URI].token);
+	p += wsi->utf8_token[WSI_TOKEN_GET_URI].token_len;
+
+	if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
+		strcpy(p,   "\x0d\x0aSec-WebSocket-Protocol: ");
+		p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
+		strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
+		p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
+	}
+
+	strcpy(p,   "\x0d\x0a\x0d\x0a");
+	p += strlen("\x0d\x0a\x0d\x0a");
+
+	/* convert the two keys into 32-bit integers */
+
+	if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
+		goto bail;
+	if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
+		goto bail;
+
+	/* lay them out in network byte order (MSB first */
+
+	sum[0] = key1 >> 24;
+	sum[1] = key1 >> 16;
+	sum[2] = key1 >> 8;
+	sum[3] = key1;
+	sum[4] = key2 >> 24;
+	sum[5] = key2 >> 16;
+	sum[6] = key2 >> 8;
+	sum[7] = key2;
+
+	/* follow them with the challenge token we were sent */
+
+	memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
+
+	/*
+	 * compute the md5sum of that 16-byte series and use as our
+	 * payload after our headers
+	 */
+
+	MD5(sum, 16, (unsigned char *)p);
+	p += 16;
+
+	/* it's complete: go ahead and send it */
+
+	debug("issuing response packet %d len\n", (int)(p - response));
+#ifdef DEBUG
+	fwrite(response, 1,  p - response, stderr);
+#endif
+	n = libwebsocket_write(wsi, (unsigned char *)response,
+					  p - response, LWS_WRITE_HTTP);
+	if (n < 0) {
+		fprintf(stderr, "ERROR writing to socket");
+		goto bail;
+	}
+
+	/* alright clean up and set ourselves into established state */
+
+	free(response);
+	wsi->state = WSI_STATE_ESTABLISHED;
+	wsi->lws_rx_parse_state = LWS_RXPS_NEW;
+
+	/* notify user code that we're ready to roll */
+
+	if (wsi->protocol->callback)
+		wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
+					  wsi->user_space, NULL, 0);
+
+	return 0;
+
+bail:
+	return -1;
+}
+
+/*
+ * Perform the newer BASE64-encoded handshake scheme
+ */
+
+static int
+handshake_04(struct libwebsocket *wsi)
+{
+	static const char *websocket_magic_guid_04 =
+					 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+	char buf[MAX_WEBSOCKET_04_KEY_LEN + 37];
+	unsigned char hash[20];
+	int n;
+	char *response;
+	char *p;
+	int fd;
+
+	if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
+	    !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
+	    !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
+	    !wsi->utf8_token[WSI_TOKEN_KEY].token_len)
+		/* completed header processing, but missing some bits */
+		goto bail;
+
+	if (wsi->utf8_token[WSI_TOKEN_KEY].token_len >=
+						     MAX_WEBSOCKET_04_KEY_LEN) {
+		fprintf(stderr, "Client sent handshake key longer "
+			   "than max supported %d\n", MAX_WEBSOCKET_04_KEY_LEN);
+		goto bail;
+	}
+
+	strcpy(buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
+	strcpy(buf + wsi->utf8_token[WSI_TOKEN_KEY].token_len,
+						       websocket_magic_guid_04);
+
+	SHA1((unsigned char *)buf, wsi->utf8_token[WSI_TOKEN_KEY].token_len +
+					 strlen(websocket_magic_guid_04), hash);
+
+	n = lws_b64_encode_string((char *)hash, buf, sizeof buf);
+	if (n < 0) {
+		fprintf(stderr, "Base64 encoded hash too long\n");
+		goto bail;
+	}
+
+	/* allocate the per-connection user memory (if any) */
+
+	if (wsi->protocol->per_session_data_size) {
+		wsi->user_space = malloc(
+				  wsi->protocol->per_session_data_size);
+		if (wsi->user_space  == NULL) {
+			fprintf(stderr, "Out of memory for "
+						   "conn user space\n");
+			goto bail;
+		}
+	} else
+		wsi->user_space = NULL;
+
+	/* create the response packet */
+
+	/* make a buffer big enough for everything */
+
+	response = malloc(256 +
+		wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
+		wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
+		wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
+	if (!response) {
+		fprintf(stderr, "Out of memory for response buffer\n");
+		goto bail;
+	}
+
+	p = response;
+	strcpy(p,   "HTTP/1.1 101 Switching Protocols\x0d\x0a"
+					  "Upgrade: WebSocket\x0d\x0a");
+	p += strlen("HTTP/1.1 101 Switching Protocols\x0d\x0a"
+					  "Upgrade: WebSocket\x0d\x0a");
+	strcpy(p,   "Connection: Upgrade\x0d\x0a"
+		    "Sec-WebSocket-Accept: ");
+	p += strlen("Connection: Upgrade\x0d\x0a"
+		    "Sec-WebSocket-Accept: ");
+	strcpy(p, buf);
+	p += n;
+
+	/* select the nonce */
+
+	fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
+	if (fd < 1) {
+		fprintf(stderr, "Unable to open random device %s\n",
+							SYSTEM_RANDOM_FILEPATH);
+		free(wsi->user_space);
+		goto bail;
+	}
+	n = read(fd, hash, 16);
+	if (n != 16) {
+		fprintf(stderr, "Unable to read from random device %s\n",
+							SYSTEM_RANDOM_FILEPATH);
+		free(wsi->user_space);
+		goto bail;
+	}
+	close(fd);
+
+	/* encode the nonce */
+
+	n = lws_b64_encode_string((const char *)hash, buf, sizeof buf);
+	if (n < 0) {
+		fprintf(stderr, "Failed to base 64 encode the nonce\n");
+		free(wsi->user_space);
+		goto bail;
+	}
+
+	/* apply the nonce */
+
+	strcpy(p, buf);
+	p += n;
+
+	if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
+		strcpy(p,   "\x0d\x0aSec-WebSocket-Protocol: ");
+		p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
+		strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
+		p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
+	}
+
+	/* end of response packet */
+
+	strcpy(p,   "\x0d\x0a\x0d\x0a");
+	p += strlen("\x0d\x0a\x0d\x0a");
+
+	debug("issuing response packet %d len\n", (int)(p - response));
+#ifdef DEBUG
+	fwrite(response, 1,  p - response, stderr);
+#endif
+	n = libwebsocket_write(wsi, (unsigned char *)response,
+					  p - response, LWS_WRITE_HTTP);
+	if (n < 0) {
+		fprintf(stderr, "ERROR writing to socket");
+		goto bail;
+	}
+
+	/* alright clean up and set ourselves into established state */
+
+	free(response);
+	wsi->state = WSI_STATE_ESTABLISHED;
+	wsi->lws_rx_parse_state = LWS_RXPS_NEW;
+
+	/* notify user code that we're ready to roll */
+
+	if (wsi->protocol->callback)
+		wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
+					  wsi->user_space, NULL, 0);
+
+	return 0;
+
+
+bail:
+	return -1;
+}
+
+
 /*
  * -04 of the protocol (actually the 80th version) has a radically different
  * handshake.  The 04 spec gives the following idea
@@ -83,7 +386,7 @@ interpret_key(const char *key, unsigned long *result)
  *      Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
  *      Sec-WebSocket-Origin: http://example.com
  *      Sec-WebSocket-Protocol: chat, superchat
- * 	Sec-WebSocket-Version: 4
+ *	Sec-WebSocket-Version: 4
  *
  *  The handshake from the server looks as follows:
  *
@@ -106,10 +409,6 @@ int
 libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
 {
 	size_t n;
-	char *p;
-	unsigned long key1, key2;
-	unsigned char sum[16];
-	char *response;
 
 	switch (wsi->state) {
 	case WSI_STATE_HTTP:
@@ -140,34 +439,11 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
 			return 0;
 		}
 
-		/* Websocket - confirm we have all the necessary pieces */
-
-		if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
-			!wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
-			!wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
-			!wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
-				     !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
-			/* completed header processing, but missing some bits */
-			goto bail;
-
-		/* are we happy about the draft version client side wants? */
-
-		if (wsi->utf8_token[WSI_TOKEN_DRAFT].token) {
-			wsi->ietf_spec_revision =
-				   atoi(wsi->utf8_token[WSI_TOKEN_DRAFT].token);
-			switch (wsi->ietf_spec_revision) {
-			case 76:
-			case 3:
-				break;
-			default:
-				fprintf(stderr, "Rejecting handshake on seeing "
-					"unsupported draft request %d\n",
-						       wsi->ietf_spec_revision);
-				goto bail;
-			}
-		}
-
-		/* Make sure user side is happy about protocol */
+		/*
+		 * It's websocket
+		 *
+		 * Make sure user side is happy about protocol
+		 */
 
 		while (wsi->protocol->callback) {
 
@@ -196,126 +472,35 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
 			goto bail;
 		}
 
-		/* allocate the per-connection user memory (if any) */
-
-		if (wsi->protocol->per_session_data_size) {
-			wsi->user_space = malloc(
-					  wsi->protocol->per_session_data_size);
-			if (wsi->user_space  == NULL) {
-				fprintf(stderr, "Out of memory for "
-							   "conn user space\n");
-				goto bail;
-			}
-		} else
-			wsi->user_space = NULL;
-
-		/* create the response packet */
-
-		/* make a buffer big enough for everything */
-
-		response = malloc(256 +
-			wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
-			wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
-			wsi->utf8_token[WSI_TOKEN_HOST].token_len +
-			wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
-			wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
-			wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
-		if (!response) {
-			fprintf(stderr, "Out of memory for response buffer\n");
-			goto bail;
-		}
-
-		p = response;
-		strcpy(p,   "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
-						  "Upgrade: WebSocket\x0d\x0a");
-		p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
-						  "Upgrade: WebSocket\x0d\x0a");
-		strcpy(p,   "Connection: Upgrade\x0d\x0a"
-			    "Sec-WebSocket-Origin: ");
-		p += strlen("Connection: Upgrade\x0d\x0a"
-			    "Sec-WebSocket-Origin: ");
-		strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
-		p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
-#ifdef LWS_OPENSSL_SUPPORT
-		if (use_ssl) {
-			strcpy(p,   "\x0d\x0aSec-WebSocket-Location: wss://");
-			p += strlen("\x0d\x0aSec-WebSocket-Location: wss://");
-		} else {
-#endif
-			strcpy(p,   "\x0d\x0aSec-WebSocket-Location: ws://");
-			p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
-#ifdef LWS_OPENSSL_SUPPORT
-		}
-#endif
-		strcpy(p, wsi->utf8_token[WSI_TOKEN_HOST].token);
-		p += wsi->utf8_token[WSI_TOKEN_HOST].token_len;
-		strcpy(p, wsi->utf8_token[WSI_TOKEN_GET_URI].token);
-		p += wsi->utf8_token[WSI_TOKEN_GET_URI].token_len;
-
-		if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
-			strcpy(p,   "\x0d\x0aSec-WebSocket-Protocol: ");
-			p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
-			strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
-			p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
-		}
-
-		strcpy(p,   "\x0d\x0a\x0d\x0a");
-		p += strlen("\x0d\x0a\x0d\x0a");
-
-		/* convert the two keys into 32-bit integers */
-
-		if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
-			goto bail;
-		if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
-			goto bail;
-
-		/* lay them out in network byte order (MSB first */
-
-		sum[0] = key1 >> 24;
-		sum[1] = key1 >> 16;
-		sum[2] = key1 >> 8;
-		sum[3] = key1;
-		sum[4] = key2 >> 24;
-		sum[5] = key2 >> 16;
-		sum[6] = key2 >> 8;
-		sum[7] = key2;
-
-		/* follow them with the challenge token we were sent */
-
-		memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
-
 		/*
-		 * compute the md5sum of that 16-byte series and use as our
-		 * payload after our headers
+		 * find out which spec version the client is using
+		 * if this header is not given, we default to 00 (aka 76)
 		 */
 
-		MD5(sum, 16, (unsigned char *)p);
-		p += 16;
+		if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len)
+			wsi->ietf_spec_revision =
+				 atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token);
 
-		/* it's complete: go ahead and send it */
+		/*
+		 * Websocket 04+?
+		 * confirm we have all the necessary pieces
+		 */
 
-		debug("issuing response packet %d len\n", (int)(p - response));
-#ifdef DEBUG
-		fwrite(response, 1,  p - response, stderr);
-#endif
-		n = libwebsocket_write(wsi, (unsigned char *)response,
-						  p - response, LWS_WRITE_HTTP);
-		if (n < 0) {
-			fprintf(stderr, "ERROR writing to socket");
+		switch (wsi->ietf_spec_revision) {
+		case 0: /* applies to 76 and 00 */
+			if (handshake_76(wsi))
+				goto bail;
+			break;
+		case 4: /* 04 */
+			if (handshake_04(wsi))
+				goto bail;
+			break;
+		default:
+			fprintf(stderr, "Unknown client spec version %d\n",
+						       wsi->ietf_spec_revision);
 			goto bail;
 		}
 
-		/* alright clean up and set ourselves into established state */
-
-		free(response);
-		wsi->state = WSI_STATE_ESTABLISHED;
-		wsi->lws_rx_parse_state = LWS_RXPS_NEW;
-
-		/* notify user code that we're ready to roll */
-
-		if (wsi->protocol->callback)
-			wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
-						  wsi->user_space, NULL, 0);
 		break;
 
 	case WSI_STATE_ESTABLISHED:
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 6917d1e4..742afa7a 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -603,12 +603,12 @@ int libwebsocket_create_server(int port,
 			this->wsi[this->fds_count]->user_space = NULL;
 
 			/*
-			 * Default protocol is 76
+			 * Default protocol is 76 / 00
 			 * After 76, there's a header specified to inform which
 			 * draft the client wants, when that's seen we modify
 			 * the individual connection's spec revision accordingly
 			 */
-			this->wsi[this->fds_count]->ietf_spec_revision = 76;
+			this->wsi[this->fds_count]->ietf_spec_revision = 0;
 
 fill_in_fds:
 
diff --git a/lib/parsers.c b/lib/parsers.c
index 64725828..f153790d 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -203,11 +203,11 @@ static int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
 
 		switch (wsi->ietf_spec_revision) {
 		/* Firefox 4.0b6 likes this as of 30 Oct */
-		case 76:
+		case 0:
 			if (c == 0xff)
 				wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
 			break;
-		case 0:
+		case 4:
 			break;
 		}
 
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 2d02cc2c..8001a06a 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -46,6 +46,7 @@
 #endif
 
 #include <openssl/md5.h>
+#include <openssl/sha.h>
 #include "libwebsockets.h"
 
 /* #define DEBUG  */
@@ -73,6 +74,9 @@ extern int use_ssl;
 #define MAX_BROADCAST_PAYLOAD 1024
 #define LWS_MAX_PROTOCOLS 10
 
+#define MAX_WEBSOCKET_04_KEY_LEN 128
+#define SYSTEM_RANDOM_FILEPATH "/dev/random"
+
 enum lws_connection_states {
 	WSI_STATE_HTTP,
 	WSI_STATE_HTTP_HEADERS,