X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/b13fa4448f517b46e917c5145050f434d6df24d5..1ec412d97ddac6bd184c645815037e29fd84fb90:/client/scripts/mfkeys.lua?ds=sidebyside

diff --git a/client/scripts/mfkeys.lua b/client/scripts/mfkeys.lua
index f40b2be2..804b6115 100644
--- a/client/scripts/mfkeys.lua
+++ b/client/scripts/mfkeys.lua
@@ -7,19 +7,76 @@
 	the license.
 	
 	Copyright (C) 2013 m h swende <martin at swende.se>
-]]
+--]]
 -- Loads the commands-library
 local cmds = require('commands')
 -- Load the default keys
 local keys = require('mf_default_keys')
 -- Ability to read what card is there
 local reader = require('read14a')
+local getopt = require('getopt')
+
+local OR = bit32.bor
+local LSHIFT = bit32.lshift
 
-local desc = 
-("This script implements check keys. It utilises a large list of default keys (currently %d keys).\
-If you want to add more, just put them inside mf_default_keys.lua. "):format(#keys)
+example =[[
+	 script run mfkeys
+]]
+author = "Iceman"
+usage = "script run mfkeys"
+desc = ("This script implements Mifare check keys. It utilises a large list of default keys (currently %d keys).\
+If you want to add more, just put them inside /lualibs/mf_default_keys.lua\n"):format(#keys) ..
+[[
+
+Arguments:
+	-h             : this help
+]]
 
 local TIMEOUT = 10000 -- 10 seconds
+--- 
+-- Usage help
+function help()
+	print(desc)
+	print("Example usage")
+	print(example)
+end
+	
+--[[This may be moved to a separate library at some point]]
+local utils = 
+{
+	--- 
+	-- Asks the user for Yes or No
+	confirm = function(message, ...)
+		local answer
+		message = message .. " [y]/[n] ?"
+		repeat
+			io.write(message)
+			io.flush()
+			answer=io.read()
+			if answer == 'Y' or answer == "y" then
+				return true
+			elseif answer == 'N' or answer == 'n' then 
+				return false
+			end
+		until false
+	end,
+	---
+	-- Asks the user for input
+	input = function (message , default)
+		local answer
+		if default ~= nil then
+			message = message .. " (default: ".. default.. " )"
+		end
+		message = message .." \n > "
+		io.write(message)
+		io.flush()
+		answer=io.read()
+		if answer == '' then answer = default end
+
+		return answer
+	end,
+}
+
 
 local function checkCommand(command)
 
@@ -43,7 +100,6 @@ local function checkCommand(command)
 	end
 end
 
-
 function checkBlock(blockNo, keys, keyType)
 	-- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. 
 	-- If there's more, we need to split it up
@@ -53,12 +109,10 @@ function checkBlock(blockNo, keys, keyType)
 		local n,data = remaining, nil
 		if remaining > 85 then n = 85 end
 		local data = table.concat(keys,"",start,n)
-		--print("data",data)
-		--print("data len", #data)
 		print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n))
 		local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, 
-								arg1 = blockNo, 
-								arg2 = keyType, 
+								arg1 =  OR(blockNo, LSHIFT(keyType,8) ),
+								arg2 = 0, 
 								arg3 = n, 
 								data = data}
 		local status = checkCommand(command)
@@ -70,19 +124,19 @@ function checkBlock(blockNo, keys, keyType)
 end
 
 -- A function to display the results
+-- TODO: iceman 2016,  still screws up output when a key is not found.
 local function displayresults(results)
 	local sector, blockNo, keyA, keyB,_
 
-	print("________________________________________")
-	print("|Sector|Block|     A      |      B     |")
-	print("|--------------------------------------|")
+	print("|---|----------------|---|----------------|---|")
+	print("|sec|key A           |res|key B           |res|")
+	print("|---|----------------|---|----------------|---|")
 
 	for sector,_ in pairs(results) do
 		blockNo, keyA, keyB = unpack(_)
-
-		print(("| %3d  | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB ))
+		print(("|%03d|  %s  | 1 |  %s  | 1 |"):format(sector, keyA, keyB ))
 	end
-	print("|--------------------------------------|")
+	print("|---|----------------|---|----------------|---|")
 
 end
 -- A little helper to place an item first in the list
@@ -101,28 +155,73 @@ local function placeFirst(akey, list)
 	end
 	return result
 end
+local function dumptofile(results)
+	local sector, blockNo, keyA, keyB,_
 
-local function main()
+	if utils.confirm("Do you wish to save the keys to dumpfile?") then 
+		local destination = utils.input("Select a filename to store to", "dumpkeys.bin")
+		local file = io.open(destination, "w")
+		if file == nil then 
+			print("Could not write to file ", destination)
+			return
+		end
 
-	print(desc);
+		local key_a = ""
+		local key_b = ""
+		
+		for sector,_ in pairs(results) do
+			blockNo, keyA, keyB = unpack(_)
+			key_a = key_a .. bin.pack("H",keyA);
+			key_b = key_b .. bin.pack("H",keyB);
+		end
+		file:write(key_a)
+		file:write(key_b)
+		file:close()
+	end
+end
+
+local function main( args)
 
+	-- Arguments for the script
+	for o, a in getopt.getopt(args, 'h') do
+		if o == "h" then return help() end			
+	end
+	
 	result, err = reader.read1443a()
 	if not result then
 		print(err)
 		return
 	end
-	print(("Found a %s tag"):format(result.name))
 
+	print(("Found a %s tag"):format(result.name))
 
 	core.clearCommandBuffer()
 	local blockNo
 	local keyType = 0 -- A=0, B=1
-	local result = {}
-	for sector=1,40,1 do
+	local numSectors = 16 
+
+	if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k
+		-- IFARE Classic 4K offers 4096 bytes split into forty sectors, 
+		-- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. 
+		numSectors = 40
+	elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
+		-- 1K offers 1024 bytes of data storage, split into 16 sector
+		numSectors = 16
+	elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
+		-- MIFARE Classic mini offers 320 bytes split into five sectors.
+		numSectors = 5
+	elseif  0x10 == result.sak then-- "NXP MIFARE Plus 2k"
+		numSectors = 32
+	else
+		print("I don't know how many sectors there are on this type of card, defaulting to 16")
+	end
+
+	result = {}
+	for sector=1,numSectors,1 do
 
 		--[[
-		The mifare Classic 1k card has 16 sectors of 4 data blocks each. The
-		first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
+		The mifare Classic 1k card has 16 sectors of 4 data blocks each. 
+		The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
 		8 sectors consist of 16 data blocks. 
 		--]]
 		local blockNo = sector * 4 -1 
@@ -148,7 +247,8 @@ local function main()
 		end
 	end
 	displayresults(result)
+	dumptofile(result)
 end
 
-main()
+main( args)