mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-22 06:13:27 -07:00
added WritePerso() method to personalize the keys and data on the card before moving security levels.
This commit is contained in:
parent
8987480b61
commit
53ef1227c4
1 changed files with 96 additions and 7 deletions
|
@ -1,6 +1,13 @@
|
||||||
local cmds = require('commands')
|
local cmds = require('commands')
|
||||||
local lib14a = require('read14a')
|
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
|
-- This is only meant to be used when errors occur
|
||||||
|
@ -30,13 +37,96 @@ function sendRaw(rawdata, crc, power)
|
||||||
if result then
|
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
|
--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)
|
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
|
else
|
||||||
err = "Error sending the card raw data."
|
err = "Error sending the card raw data."
|
||||||
oops(err)
|
oops(err)
|
||||||
end
|
end
|
||||||
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
|
-- The main entry point
|
||||||
function main(args)
|
function main(args)
|
||||||
|
@ -49,13 +139,12 @@ function main(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Now that the card is initialized, attempt to send raw data and read the response.
|
-- 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_INIT, true, true)
|
||||||
sendRaw(GETVERS_CONT, true, true)
|
--sendRaw(GETVERS_CONT, true, true)
|
||||||
sendRaw(GETVERS_CONT, true, true)
|
--sendRaw(GETVERS_CONT, true, true)
|
||||||
|
|
||||||
|
writePerso()
|
||||||
|
|
||||||
sendRaw(POWEROFF, false, false) --power off the Proxmark
|
sendRaw(POWEROFF, false, false) --power off the Proxmark
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue