diff --git a/scripts/ssl-enum-ciphers.nse b/scripts/ssl-enum-ciphers.nse
index eeedcca..88d13b5 100644
--- a/scripts/ssl-enum-ciphers.nse
+++ b/scripts/ssl-enum-ciphers.nse
@@ -542,8 +542,11 @@ local function client_hello(t)
 	if t["compressors"] ~= nil then
 		-- Add specified compressors.
 		for _, compressor in pairs(t["compressors"]) do
-			compressors = compressors .. bin.pack("C", COMPRESSORS[compressor])
+      if compressor ~= "NULL" then
+        compressors = compressors .. bin.pack("C", COMPRESSORS[compressor])
+      end
 		end
+    compressors = compressors .. bin.pack("C", 0) -- Always include NULL as last choice
 	else
 		-- Add all known compressors.
 		for _, compressor in pairs(COMPRESSORS) do
@@ -569,9 +572,8 @@ local function client_hello(t)
 	return record_write("handshake", t["protocol"], h .. b)
 end
 
-local function try_params(host, port, t, name, records)
+local function try_params(host, port, t)
 	local buffer, err, i, record, req, resp, sock, status
-	local condvar = nmap.condvar(records)
 
 	-- Create socket.
 	sock = nmap.new_socket()
@@ -580,7 +582,6 @@ local function try_params(host, port, t, name, records)
 	if not status then
 		stdnse.print_debug(1, "Can't connect: %s", err)
 		sock:close()
-		condvar "signal"
 		return nil
 	end
 
@@ -590,7 +591,6 @@ local function try_params(host, port, t, name, records)
 	if not status then
 		stdnse.print_debug(1, "Can't send: %s", err)
 		sock:close()
-		condvar "signal"
 		return nil
 	end
 
@@ -602,8 +602,7 @@ local function try_params(host, port, t, name, records)
 		status, resp = sock:receive()
 		if not status then
 			sock:close()
-			condvar "signal"
-			return record
+			return nil
 		end
 
 		buffer = buffer .. resp
@@ -612,159 +611,181 @@ local function try_params(host, port, t, name, records)
 		i, record = record_read(buffer, i)
 		if record ~= nil then
 			sock:close()
-			record.name = name
-			table.insert(records, record)
-			condvar "signal"
-			return
+			return record
 		end
 	end
 end
 
-local function try_protocol(host, port, protocol)
-	local ciphers, compressors, results
+local function keys(t)
+  local ret = {}
+  for k, _ in pairs(t) do
+    ret[#ret+1] = k
+  end
+  return ret
+end
+
+local function keys_in_chunks(t)
+  local ret = {{}}
+  local c = 0
+  local b = 1
+  for k, _ in pairs(t) do
+    c = c+1
+    ret[b][c] = k
+    if c > 64 then
+      c = 0
+      b = b + 1
+      ret[b] = {}
+    end
+  end
+  return ret
+end
+
+local function remove(t, e)
+  for i, v in ipairs(t) do
+    if v == e then
+      table.remove(t, i)
+      return i
+    end
+  end
+  return nil
+end
 
-	local function find_ciphers()
-		local name, protocol_worked, record, results, t,cipherstr
-		local records, threads = {}, {}
-		local condvar = nmap.condvar(records)
+local function find_ciphers(host, port, protocol)
+  local name, protocol_worked, record, results, t,cipherstr
+  local ciphers = keys_in_chunks(CIPHERS)
 
-		results = {}
+  results = {}
 
-		-- Try every cipher.
-		protocol_worked = false
-		for name, _ in pairs(CIPHERS) do
+  -- Try every cipher.
+  protocol_worked = false
+  for i, group in ipairs(ciphers) do
+    stdnse.print_debug(1, "Starting group %d", i)
+    while (next(group)) do
+      stdnse.print_debug(1, "%d ciphers left", #group)
 			-- Create structure.
 			t = {
-				["ciphers"] = {name},
+				["ciphers"] = group,
 				["protocol"] = protocol
 			}
 
-			-- Try connecting with cipher.
-			local co = stdnse.new_thread(try_params, host, port, t, name, records)
-			threads[co] = true
-		end
+      record = try_params(host, port, t)
 		
-		repeat
-			for thread in pairs(threads) do
-				if coroutine.status(thread) == "dead" then threads[thread] = nil end
-			end
-			if ( next(threads) ) then
-				condvar "wait"
-			end
-		until next(threads) == nil
-			
-		
-		for _, record in ipairs(records) do
-			local name = record.name
 			if record == nil then
 				if protocol_worked then
-					stdnse.print_debug(2, "Cipher %s rejected.", name)
+					stdnse.print_debug(1, "%d ciphers rejected in group %d. (No handshake)", #group, i)
 				else
-					stdnse.print_debug(2, "Cipher %s and/or protocol %s rejected.", name, protocol)
+					stdnse.print_debug(1, "%d ciphers in group %d and/or protocol %s rejected. (No handshake)", #group, i, protocol)
 				end
+        break
 			elseif record["protocol"] ~= protocol then
 				stdnse.print_debug(1, "Protocol %s rejected.", protocol)
+        protocol_worked = nil
 				break
 			elseif record["type"] == "alert" and record["body"]["description"] == "handshake_failure" then
 				protocol_worked = true
-				stdnse.print_debug(2, "Cipher %s rejected.", name)
+				stdnse.print_debug(2, "%d ciphers rejected in group %d.", #group, i)
+        break
 			elseif record["type"] ~= "handshake" or record["body"]["type"] ~= "server_hello" then
 				stdnse.print_debug(2, "Unexpected record received.")
+        break
 			else
 				protocol_worked = true
+				name = record["body"]["cipher"]
 				stdnse.print_debug(2, "Cipher %s chosen.", name)
+        remove(group, name)
 
 				-- Add cipher to the list of accepted ciphers.
-				name = record["body"]["cipher"]
-				if rankedciphersfilename and rankedciphers[name] then
-					cipherstr=rankedciphers[name]
-				else
-					cipherstr="unknown strength"
-				end
-				stdnse.print_debug(2, "Strength of %s rated %d.",cipherstr,cipherstrength[cipherstr])
-				if mincipherstrength>cipherstrength[cipherstr] then
-					stdnse.print_debug(2, "Downgrading min cipher strength to %d.",cipherstrength[cipherstr])
-					mincipherstrength=cipherstrength[cipherstr]
-				end
-				name=name.." - "..cipherstr
 				table.insert(results, name)
 			end
 		end
+    if protocol_worked == nil then break end
+  end
 
-		return results
-	end
-
-	local function find_compressors()
-		local name, protocol_worked, record, results, t
-		local records, threads = {}, {}
-		local condvar = nmap.condvar(records)
-
-		results = {}
-
-		-- Try every compressor.
-		protocol_worked = false
-		for name, _ in pairs(COMPRESSORS) do
-			-- Create structure.
-			t = {
-				["compressors"] = {name},
-				["protocol"] = protocol
-			}
-
-			-- Try connecting with compressor.
-			local co = stdnse.new_thread(try_params, host, port, t, name, records)
-			threads[co] = true
-		end
-		
-		repeat
-			for thread in pairs(threads) do
-				if coroutine.status(thread) == "dead" then threads[thread] = nil end
-			end
-			if ( next(threads) ) then
-				condvar "wait"
-			end
-		until next(threads) == nil
-		
-		for _, record in ipairs(records) do
-			local name = record.name
-			if record == nil then
-				if protocol_worked then
-					stdnse.print_debug(2, "Compressor %s rejected.", name)
-				else
-					stdnse.print_debug(2, "Compressor %s and/or protocol %s rejected.", name, protocol)
-				end
-			elseif record["protocol"] ~= protocol then
-				stdnse.print_debug(1, "Protocol %s rejected.", protocol)
-				break
-			elseif record["type"] == "alert" and record["body"]["description"] == "handshake_failure" then
-				protocol_worked = true
-				stdnse.print_debug(2, "Compressor %s rejected.", name)
-			elseif record["type"] ~= "handshake" or record["body"]["type"] ~= "server_hello" then
-				stdnse.print_debug(2, "Unexpected record received.")
-			elseif record["body"]["compressor"] ~= name then
-				protocol_worked = true
-				stdnse.print_debug(2, "Compressor %s rejected.", name)
-			else
-				protocol_worked = true
-				stdnse.print_debug(2, "Compressor %s chosen.", name)
+  return results
+end
 
-				-- Add compressor to the list of accepted compressors.
-				table.insert(results, name)
-			end
-		end
+local function find_compressors(host, port, protocol, good_cipher)
+  local name, protocol_worked, record, results, t
+  local compressors = keys(COMPRESSORS)
+
+  results = {}
+
+  -- Try every compressor.
+  protocol_worked = false
+  while (next(compressors)) do
+    -- Create structure.
+    t = {
+      ["compressors"] = compressors,
+      ["ciphers"] = {good_cipher},
+      ["protocol"] = protocol
+    }
+
+    -- Try connecting with compressor.
+    record = try_params(host, port, t)
+  
+    if record == nil then
+      if protocol_worked then
+        stdnse.print_debug(1, "%d compressors rejected. (No handshake)", #compressors)
+      else
+        stdnse.print_debug(1, "%d compressors and/or protocol %s rejected. (No handshake)", #compressors, protocol)
+      end
+      break
+    elseif record["protocol"] ~= protocol then
+      stdnse.print_debug(1, "Protocol %s rejected.", protocol)
+      break
+    elseif record["type"] == "alert" and record["body"]["description"] == "handshake_failure" then
+      protocol_worked = true
+      stdnse.print_debug(2, "%d compressors rejected.", #compressors)
+      break
+    elseif record["type"] ~= "handshake" or record["body"]["type"] ~= "server_hello" then
+      stdnse.print_debug(2, "Unexpected record received.")
+      break
+    else
+      protocol_worked = true
+      name = record["body"]["compressor"]
+      stdnse.print_debug(2, "Compressor %s chosen.", name)
+      remove(compressors, name)
+
+      -- Add compressor to the list of accepted compressors.
+      table.insert(results, name)
+      if name == "NULL" then
+        break -- NULL is always last choice, and must be included
+      end
+    end
+  end
+
+  return results
+end
 
-		return results
-	end
+local function try_protocol(host, port, protocol, upresults)
+	local ciphers, compressors, results
+  local condvar = nmap.condvar(upresults)
 
 	results = {}
 
 	-- Find all valid ciphers.
-	ciphers = find_ciphers()
+	ciphers = find_ciphers(host, port, protocol)
 	if #ciphers == 0 then
-		return {}
+    condvar "signal"
+    return nil
 	end
-
 	-- Find all valid compression methods.
-	compressors = find_compressors()
+	compressors = find_compressors(host, port, protocol, ciphers[1])
+
+  -- Add rankings to ciphers
+  for i, name in ipairs(ciphers) do
+    if rankedciphersfilename and rankedciphers[name] then
+      cipherstr=rankedciphers[name]
+    else
+      cipherstr="unknown strength"
+    end
+    stdnse.print_debug(2, "Strength of %s rated %d.",cipherstr,cipherstrength[cipherstr])
+    if mincipherstrength>cipherstrength[cipherstr] then
+      stdnse.print_debug(2, "Downgrading min cipher strength to %d.",cipherstrength[cipherstr])
+      mincipherstrength=cipherstrength[cipherstr]
+    end
+    ciphers[i]=name.." - "..cipherstr
+  end
 
 	-- Format the cipher table.
 	table.sort(ciphers)
@@ -776,7 +797,12 @@ local function try_protocol(host, port, protocol)
 	compressors["name"] = "Compressors (" .. #compressors .. ")"
 	table.insert(results, compressors)
 
-	return results
+  if #results > 0 then
+    results["name"] = protocol
+    table.insert(upresults, results)
+  end
+  condvar "signal"
+  return nil
 end
 
 -- Shamelessly stolen from nselib/unpwdb.lua and changed a bit. (Gabriel Lawrence)
@@ -830,15 +856,24 @@ action = function(host, port)
 
 	results = {}
 
+  local condvar = nmap.condvar(results)
+  local threads = {}
+
 	for name, _ in pairs(PROTOCOLS) do
 		stdnse.print_debug(1, "Trying protocol %s.", name)
-		result = try_protocol(host.ip, port.number, name)
-		if #result > 0 then
-			result["name"] = name
-			table.insert(results, result)
-		end
+		local co = stdnse.new_thread(try_protocol, host.ip, port.number, name, results)
+    threads[co] = true
 	end
 
+  repeat
+    for thread in pairs(threads) do
+      if coroutine.status(thread) == "dead" then threads[thread] = nil end
+    end
+    if ( next(threads) ) then
+      condvar "wait"
+    end
+  until next(threads) == nil
+
 	-- Sort protocol results by name.
 	table.sort(results, function(a, b) return a["name"] < b["name"] end)
 	if rankedciphersfilename then
