From 53ef1227c4245846fec6fced0ec4f69ba4ab88cc Mon Sep 17 00:00:00 2001 From: Dom Date: Wed, 28 Feb 2018 11:20:36 +0000 Subject: [PATCH] added WritePerso() method to personalize the keys and data on the card before moving security levels. --- client/scripts/myscript.lua | 103 +++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 7 deletions(-) diff --git a/client/scripts/myscript.lua b/client/scripts/myscript.lua index 6949191d..cfbe0b32 100644 --- a/client/scripts/myscript.lua +++ b/client/scripts/myscript.lua @@ -1,6 +1,13 @@ local cmds = require('commands') local lib14a = require('read14a') +GETVERS_INIT = "0360" -- Begins the GetVersion command +GETVERS_CONT = "03AF" -- Continues the GetVersion command +POWEROFF = "OFF" +WRITEPERSO = "03A8" +AUTH_FIRST = "0370" +AUTH_CONT = "0372" +AUTH_NONFIRST = "0376" --- -- This is only meant to be used when errors occur @@ -30,13 +37,96 @@ function sendRaw(rawdata, crc, power) if result then --unpack the first 4 parts of the result as longs, and the last as an extremely long string to later be cut down based on arg1, the number of bytes returned local count,cmd,arg1,arg2,arg3,data = bin.unpack('LLLLH512',result) - print(("<< %s"):format(string.sub(data, 1, arg1 * 2))) -- need to multiply by 2 because the hex digits are actually two bytes when they are strings + returned_bytes = string.sub(data, 1, arg1 * 2) + print(("<< %s"):format(returned_bytes)) -- need to multiply by 2 because the hex digits are actually two bytes when they are strings + return returned_bytes else err = "Error sending the card raw data." oops(err) end end +function writePerso() + -- Used to write any data, including the keys (Key A and Key B), for all the sectors. + -- writePerso() command parameters: + -- 1 byte - 0xA8 - Command Code + -- 2 bytes - Address of the first block or key to be written to (40 blocks are numbered from 0x0000 to 0x00FF) + -- X bytes - The data bytes to be written, starting from the first block. Amount of data sent can be from 16 to 240 bytes in 16 byte increments. This allows + -- up to 15 blocks to be written at once. + -- response from PICC: + -- 0x90 - OK + -- 0x09 - targeted block is invalid for writes, i.e. block 0, which contains manufacturer data + -- 0x0B - command invalid + -- 0x0C - unexpected command length + + SIXTEEN_BYTES_ZEROS = "00000000000000000000000000000000" + + -- First, set all the data in the card (4kB of data) to zeros. The keys, stored in the sector trailer block, are also set to zeros. + -- The only block which cannot be explicitly set is block 0x0000, the manufacturer block. + print("Setting values of normal blocks") + for i=1,255,1 do --skip block 0 + --convert the number to hex with leading zeros, then use it as the block number in writeBlock() + blocknum = string.format("%04x", i) + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + end + print("Finished setting values of normal blocks") + + print("Setting AES Sector keys") + -- Next, write to the AES sector keys + for i=0,39 do --for each sector number + local keyA_block = "40" .. string.format("%02x", i * 2) + local keyB_block = "40" .. string.format("%02x", (i * 2) + 1) + --Can also calculate the keys fancily to make them unique, if desired + keyA = SIXTEEN_BYTES_ZEROS + keyB = SIXTEEN_BYTES_ZEROS + writeBlock(keyA_block, keyA) + writeBlock(keyB_block, keyB) + end + print("Finished setting AES Sector keys") + + print("Setting misc keys which haven't been set yet.") + --CardMasterKey + blocknum = "9000" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --CardConfigurationKey + blocknum = "9001" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L3SwitchKey + blocknum = "9003" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --SL1CardAuthKey + blocknum = "9004" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L3SectorSwitchKey + blocknum = "9006" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L1L3MixSectorSwitchKey + blocknum = "9007" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + print("Finished setting misc keys.") + + print("WritePerso finished! Card is ready to move into new security level.") +end + +function writeBlock(blocknum, data) + -- Method writes 16 bytes of the string sent (data) to the specified block number + -- The block numbers sent to the card need to be in little endian format (i.e. block 0x0001 is sent as 0x1000) + blocknum_little_endian = string.sub(blocknum, 3, 4) .. string.sub(blocknum, 1, 2) + commandString = WRITEPERSO .. blocknum_little_endian .. data --Write 16 bytes (32 hex chars). + local response = sendRaw(commandString, true, true) --0x90 is returned upon success + if string.sub(response, 3, 4) ~= "90" then + oops(("error occurred while trying to write to block %s"):format(blocknum)) + end +end + +function authenticateAES() + -- Used to try to authenticate with the AES keys we programmed into the card, to ensure the authentication works correctly while still in SL0. + commandString = AUTH_FIRST + commandString = commandString .. "" + + +end + --- -- The main entry point function main(args) @@ -49,13 +139,12 @@ function main(args) end -- Now that the card is initialized, attempt to send raw data and read the response. - GETVERS_INIT = "0360" -- Begins the GetVersion command - GETVERS_CONT = "03AF" -- Continues the GetVersion command - POWEROFF = "OFF" - sendRaw(GETVERS_INIT, true, true) - sendRaw(GETVERS_CONT, true, true) - sendRaw(GETVERS_CONT, true, true) + --sendRaw(GETVERS_INIT, true, true) + --sendRaw(GETVERS_CONT, true, true) + --sendRaw(GETVERS_CONT, true, true) + + writePerso() sendRaw(POWEROFF, false, false) --power off the Proxmark