Closed cefn closed 7 years ago
OK I've made progress on this question and I have a reference implementation which reads all sectors and writes to every legitimate sector of a Mifare Classic 1k card. This is based on
The issue I was having was that by default the routine I was using to check sector write then read was trying to write to 0 which it shouldn't do, and this was killing the procedure, not that there was anything wrong with the keys or the addressing model.
I suspect I am doing more auth than I need to in this implementation since auth appears to be handled on a block level, when I understand from other documentation that unlocking happens on a sector level.
import mfrc522
from os import uname
if uname()[0] == 'WiPy':
rdr = mfrc522.MFRC522("GP14", "GP16", "GP15", "GP22", "GP17")
elif uname()[0] == 'esp8266':
rdr = mfrc522.MFRC522(0, 2, 4, 5, 14)
else:
raise RuntimeError("Unsupported")
def read_once():
print("Place card")
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
print("Detected")
print("type: 0x%02x" % tag_type)
print("uid: 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]))
print("")
if rdr.select_tag(raw_uid) == rdr.OK:
key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
for sector in range(1,64):
if rdr.auth(rdr.AUTHENT1A, sector, key, raw_uid) == rdr.OK:
print("data@%d: %s" % (sector, rdr.read(sector)))
else:
print("Auth err")
rdr.stop_crypto1()
else:
print("Select failed")
def write_once():
print("Place card")
(stat, tag_type) = rdr.request(rdr.REQIDL) # check if antenna idle
if stat == rdr.OK: # at least one card detected
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK: # able to separate a single card
print("Detected")
print("type: 0x%02x" % tag_type)
print("uid: 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]))
print("")
if rdr.select_tag(raw_uid) == rdr.OK: # identify which card you want to manipulate
key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
for blockIdx in range(64):
if blockIdx > 0 and blockIdx % 4 is not 3:
print("Writing" + str(blockIdx) + "...", end="")
if rdr.auth(rdr.AUTHENT1A, blockIdx, key, raw_uid) == rdr.OK:
stat = rdr.write(blockIdx, bytes([blockIdx for i in range(16)]))
if stat == rdr.OK:
print("Written")
else:
print("Failed")
else:
print("Auth err")
rdr.stop_crypto1() # assuming this complements select_tag
else:
print("Select failed")
def await_removal():
while True:
(stat, tag_type) = rdr.request(rdr.REQIDL) # check if antenna idle
if stat != rdr.OK:
return
def cycle():
while True:
read_once()
await_removal()
write_once()
await_removal()
On a bodge/rush job to implement something at present, but hopefully will get to a PR with improved documentation soon.
Hi there, @wendlers and thanks for giving me the confidence to combine mfrc522 with micropython in a project!
I have tested the read and write examples and they are functional on the Mifare 1k tag I have.
However, I am struggling to know, for example, how to write to any other parts of the card than '8', whatever that means. If I could figure it out, I could perhaps prepare a PR with documentation which someone could sanity-check for me.
Given in both read.py and write.py only 16 bytes are manipulated, it must be a single sector and block which is being read/written, but I cannot pin down where the block index is specified, assuming 8 is the sector. Given a specific target sector has been unlocked (via auth) I understand I should be able to write up to the first 3 blocks of 16 bytes, but mystified how to fully specify sector and block for reads and writes I am afraid.
It's not clear from the reader's method signatures, whether the write method's
addr
relates to sector or block or some combination of the two (e.g. all blocks are numbered 0-64). It can't be block as there's only 4 blocks, and the demo writes to 8. However, if that isn't the block address, I am struggling to find at which point of the api you can, for example address block 2 in sector 8.Equally, the
auth
method which unlocks access to a sector takes a 'sect' argument, but in the write.py example a 'key' is passed to it, containing multiple bytes, so that can't be the sector argument. There appears to just be a single addr argument throughout, rather than separate indexes for sector and block.All in all, I am struggling to interpret the available functions without documentation, at least identifying what the parameters represent, given you have sensibly given them short names for a low-resource environment like micropython.