add RfidAccess class

This commit is contained in:
danjperron
2021-09-15 12:48:10 -04:00
parent 037be68272
commit 683af24b6e
8 changed files with 546 additions and 51 deletions

View File

@@ -0,0 +1,91 @@
from mfrc522 import MFRC522
from RfidAccess import RfidAccess
import utime
reader = MFRC522(spi_id=0,sck=2,miso=4,mosi=3,cs=1,rst=0)
access = RfidAccess()
print("")
print("Please place card on reader")
print("")
def checksum(data):
crc = 0xc7
for byte in data:
crc ^= byte
for _ in range(8):
msb = crc & 0x80
crc = (crc << 1) & 0xff
if msb:
crc ^= 0x1d
return crc
PreviousCard = [0]
try:
while True:
reader.init()
(stat, tag_type) = reader.request(reader.REQIDL)
if stat == reader.OK:
(stat, uid) = reader.SelectTagSN()
if uid == PreviousCard:
continue
if stat == reader.OK:
print("Card detected {} uid={}".format(hex(int.from_bytes(bytes(uid),"little",False)).upper(),reader.tohexstring(uid)))
defaultKey = [255,255,255,255,255,255]
firstSectorKey = [0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5]
nextSectorKey = [0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7]
#set MAD sector
# first fill block permission
access.setTrailerAccess(keyA_Write=access.KEYB,access_Read=access.KEYAB,access_Write=access.KEYB,
keyB_Read=access.NEVER,keyB_Write=access.KEYB)
access.setBlockAccess(access.ALLBLOCK, access_Read=access.KEYAB, access_Write=access.KEYB,
access_Inc=access.NEVER, access_Dec=access.NEVER)
block3 = access.fillBlock3(keyA=firstSectorKey,keyB=defaultKey)
#Write the sector access
if reader.writeSectorBlock(uid,0,3,block3,keyA=defaultKey) == reader.ERR:
print("Writing MAD sector failed!")
else:
print(".",end="")
b1 = [0x14,0x01,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1]
b1[0] = checksum(b1[1:]) # I know this is already ok but just to demonstrate the CRC
reader.writeSectorBlock(uid,0,1,b1,keyB=defaultKey)
b2 = [0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1,0x03,0xE1]
reader.writeSectorBlock(uid,0,2,b1,keyB=defaultKey)
#set permission for all other sectors
access.setTrailerAccess(keyA_Write=access.KEYB,access_Read=access.KEYAB,access_Write=access.KEYB,
keyB_Read=access.NEVER,keyB_Write=access.KEYB)
access.setBlockAccess(access.ALLBLOCK, access_Read=access.KEYAB, access_Write=access.KEYAB,
access_Inc=access.KEYAB, access_Dec=access.KEYAB)
block3 = access.fillBlock3(keyA=nextSectorKey,keyB=defaultKey)
#Write all next sectors access
for sector in range(1,16):
if reader.writeSectorBlock(uid,sector,3,block3,keyA=defaultKey) == reader.ERR:
print("\nWriting to sector ",sector," Failed!")
break
else:
print(".",end="")
#force sector 1 to be 1 record empty
block= 16 *[0]
block[2]=0xfe
if reader.writeSectorBlock(uid,1,0,block,keyB=defaultKey) == reader.ERR:
print("Unable to set first NDEF record!")
print("\nDone.")
previousCard=uid
break
else:
PreviousCard=[0]
utime.sleep_ms(50)
except KeyboardInterrupt:
print("Bye")

View File

@@ -0,0 +1,70 @@
from mfrc522 import MFRC522
from RfidAccess import RfidAccess
import utime
reader = MFRC522(spi_id=0,sck=2,miso=4,mosi=3,cs=1,rst=0)
access = RfidAccess()
print("")
print("Please place card on reader")
print("")
PreviousCard = [0]
try:
while True:
reader.init()
(stat, tag_type) = reader.request(reader.REQIDL)
if stat == reader.OK:
(stat, uid) = reader.SelectTagSN()
if uid == PreviousCard:
continue
if stat == reader.OK:
print("Card detected {} uid={}".format(hex(int.from_bytes(bytes(uid),"little",False)).upper(),reader.tohexstring(uid)))
firstSectorKey = [0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5]
nextSectorKey = [0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7]
defaultKey = [255,255,255,255,255,255]
# set default access
access.decodeAccess(0xff,0x07,0x80)
block3 = access.fillBlock3(keyA=defaultKey,keyB=defaultKey)
print("Reset Mad Sector (first sector)")
#reset first sector
reader.writeSectorBlock(uid,0,3,block3,keyB=defaultKey)
#erase block1 and 2
datablock = 16 * [0]
reader.writeSectorBlock(uid,0,1,datablock,keyB=defaultKey)
reader.writeSectorBlock(uid,0,2,datablock,keyB=defaultKey)
#reset all other sectors
for s in range(1,16):
# permission to default
print("Reset sector ",s)
reader.writeSectorBlock(uid,s,3,block3,keyB=defaultKey)
for b in range(3):
# put all data to zero block 0,1 and 2
reader.writeSectorBlock(uid,s,b,datablock,keyB=defaultKey)
# ok dump new data
print("\n---- Dump card using defaultkeyB [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]\n")
reader.MFRC522_DumpClassic1K(uid, Start=0, End=64, keyB=defaultKey)
PreviousCard = uid
break
else:
pass
#print("Authentication error")
else:
PreviousCard=[0]
utime.sleep_ms(50)
except KeyboardInterrupt:
print("Bye")
print("Card done!")

45
Pico_example/Pico_read.py Normal file
View File

@@ -0,0 +1,45 @@
from mfrc522 import MFRC522
import utime
def uidToString(uid):
mystring = ""
for i in uid:
mystring = "%02X" % i + mystring
return mystring
reader = MFRC522(spi_id=0,sck=2,miso=4,mosi=3,cs=1,rst=0)
print("")
print("Please place card on reader")
print("")
PreviousCard = [0]
try:
while True:
reader.init()
(stat, tag_type) = reader.request(reader.REQIDL)
#print('request stat:',stat,' tag_type:',tag_type)
if stat == reader.OK:
(stat, uid) = reader.SelectTagSN()
if uid == PreviousCard:
continue
if stat == reader.OK:
print("Card detected {} uid={}".format(hex(int.from_bytes(bytes(uid),"little",False)).upper(),reader.tohexstring(uid)))
defaultKey = [255,255,255,255,255,255]
reader.MFRC522_DumpClassic1K(uid, Start=0, End=64, keyA=defaultKey)
print("Done")
PreviousCard = uid
else:
pass
else:
PreviousCard=[0]
utime.sleep_ms(50)
except KeyboardInterrupt:
pass

View File

@@ -17,7 +17,7 @@ def uidToString(uid):
reader = MFRC522(spi_id=0,sck=2,miso=4,mosi=3,cs=1,rst=0) reader = MFRC522(spi_id=0,sck=2,miso=4,mosi=3,cs=1,rst=0)
print("") print("")
print("Place card before reader to read from address 0x08") print("Please place card on reader")
print("") print("")
key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF] key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
@@ -32,7 +32,7 @@ try:
if stat == reader.OK: if stat == reader.OK:
print(uid) print(uid)
print("Card detected %s" % uidToString(uid)) print("Card detected %s" % uidToString(uid))
reader.MFRC522_DumpClassic1K(key, uid) reader.MFRC522_DumpClassic1K(uid,keyA=key)
print("Test ! writing sector 2, block 0 (absolute block(8)") print("Test ! writing sector 2, block 0 (absolute block(8)")
print("with [ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 ]") print("with [ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 ]")
absoluteBlock=8 absoluteBlock=8
@@ -43,7 +43,7 @@ try:
if status == reader.OK: if status == reader.OK:
status = reader.write(absoluteBlock,value) status = reader.write(absoluteBlock,value)
if status == reader.OK: if status == reader.OK:
reader.MFRC522_DumpClassic1K(key, uid) reader.MFRC522_DumpClassic1K(uid,keyA=key)
else: else:
print("unable to write") print("unable to write")
else: else:

View File

@@ -0,0 +1,47 @@
from mfrc522 import MFRC522
import utime
reader = MFRC522(spi_id=0,sck=2,miso=4,mosi=3,cs=1,rst=0)
print("")
print("Place card into reader")
print("")
PreviousCard = [0]
try:
while True:
reader.init()
(stat, tag_type) = reader.request(reader.REQIDL)
if stat == reader.OK:
(stat, uid) = reader.SelectTagSN()
if uid == PreviousCard:
continue
if stat == reader.OK:
print("Card detected {} uid={}".format(hex(int.from_bytes(bytes(uid),"little",False)).upper(),reader.tohexstring(uid)))
firstSectorKey = [0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5]
nextSectorKey = [0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7]
#defaultKey = [255,255,255,255,255,255]
#read MAD sector (first sector)
if reader.MFRC522_DumpClassic1K(uid, Start=0, End=4, keyA=firstSectorKey)== reader.OK:
#read the rest of the card
reader.MFRC522_DumpClassic1K(uid, Start=4, End=64, keyA=nextSectorKey)
print("Done")
PreviousCard = uid
else:
PreviousCard=[0]
utime.sleep_ms(50)
except KeyboardInterrupt:
print("Bye")

209
RfidAccess.py Normal file
View File

@@ -0,0 +1,209 @@
class RfidAccess:
NEVER = 0
KEYA = 1
KEYB = 2
KEYAB = 3
ALLBLOCK = -1
def __init__(self):
self.C1 = 0
self.C2 = 0
self.C3 = 8
self.C1_Inv = 15
self.C2_Inv = 15
self.C3_Inv = 7
self.Valid=False
def findAccessIndex(self,table,mask,accessbits):
for i in range(8):
if table[i] == accessbits:
if (i & 1) == 0 :
self.C2 = self.C2 & ~mask
else:
self.C2 = self.C2 | mask
if (i & 2) == 0 :
self.C1 = self.C1 & ~mask
else:
self.C1 = self.C1 | mask
if (i & 4) == 0:
self.C3 = self.C3 & ~mask
else:
self.C3 = self.C3 | mask
self.C1_Inv = self.C1 ^ 0xf
self.C2_Inv = self.C2 ^ 0xf
self.C3_Inv = self.C3 ^ 0xf
return True
return False
def setTrailerAccess(self,keyA_Write=KEYA, access_Read=KEYA,access_Write=KEYA,keyB_Read=KEYA,keyB_Write=KEYA):
#C1 weight 2 , C2 weight 1 , C3 weight 4
# Key A Wr Access R Access W KeyB R KEYB W
access_Index = ( (self.KEYA, self.KEYA, self.NEVER, self.KEYA,self.KEYA),
(self.NEVER,self.KEYA,self.NEVER,self.KEYA,self.NEVER),
(self.KEYB, self.KEYAB,self.NEVER,self.NEVER,self.NEVER),
(self.NEVER,self.KEYAB,self.NEVER,self.NEVER,self.NEVER),
(self.KEYA,self.KEYA,self.KEYA,self.KEYA,self.KEYA),
(self.KEYB,self.KEYAB,self.KEYB,self.NEVER,self.KEYB),
(self.NEVER,self.KEYAB,self.KEYB,self.NEVER,self.NEVER),
(self.NEVER,self.KEYAB,self.NEVER,self.NEVER,self.NEVER))
if self.findAccessIndex(access_Index,8, (keyA_Write,access_Read,access_Write,keyB_Read,keyB_Write)):
return True
else:
print("Access Trailer method not possible")
return False
def setBlockAccess(self, blockID, access_Read=KEYAB, access_Write=KEYAB, access_Inc=KEYAB, access_Dec=KEYAB):
# C1 weight 2 , C2 weight 1 , C3 weight 4
# Key Read Key Write INCREment decrement/transfer/etc
access_Blk_idx=((self.KEYAB, self.KEYAB, self.KEYAB, self.KEYAB,None),
(self.KEYAB, self.NEVER, self.NEVER, self.NEVER,None),
(self.KEYAB, self.KEYB, self.NEVER, self.NEVER,None),
(self.KEYAB, self.KEYB, self.KEYB, self.KEYAB,None),
(self.KEYAB, self.NEVER, self.NEVER, self.KEYAB,None),
(self.KEYB, self.KEYB, self.NEVER, self.NEVER,None),
(self.KEYB, self.NEVER, self.NEVER, self.NEVER,None),
(self.NEVER, self.NEVER, self.NEVER, self.NEVER,None))
if(blockID == self.ALLBLOCK):
Mask = 7
elif (BlockID<0) or (blockID >3):
return false
else:
Mask = 1 << blockID
if self.findAccessIndex(access_Blk_idx,Mask,( access_Read, access_Write, access_Inc, access_Dec, None)):
return True
else:
print("**** Error Access Block method not possible")
return False
def encodeAccess(self):
self.C1 = self.C1 & 0xf
self.C2 = self.C2 & 0xf
self.C3 = self.C3 & 0xf
self.C1_INV = self.C1 ^ 0xf
self.C2_INV = self.C2 ^ 0xf
self.C3_INV = self.C3 ^ 0xf
byte6 = self.C2_INV << 4 | self.C1_INV
byte7 = self.C1 << 4 | self.C3_INV
byte8 = self.C3 << 4 | self.C2
return (byte6, byte7, byte8)
def decodeAccess(self, byte6,byte7,byte8):
self.C1_Inv = byte6 & 0xf
self.C2_Inv = (byte6 & 0xf0) >> 4
self.C3_Inv = byte7 & 0xf
self.C1 = (byte7 & 0xf0) >> 4
self.C2 = byte8 & 0xf
self.C3 = (byte8 & 0xf0) >>4
return ((self.C1 ^ self.C1_Inv) & (self.C2 ^ self.C2_Inv) & (self.C3 ^ self.C3_Inv)) & 0xf == 0xf
def showTrailerAccess(self):
KeyAWrite = ['key A', 'never', 'key B', 'never', 'key A', 'key B', 'never', 'never']
AccessRead = ['key A', 'key A', 'key A|B', 'key A|B', 'key A','key A|B','key A|B','key A|B' ]
AccessWrite = ['never', 'never', 'never', 'never', 'key A', 'key B', 'key B', 'never']
KeyBRead = ['key A data R/W', 'key A data R', 'never', 'never', 'key A data R/W', 'never', 'never', 'never']
KeyBWrite = ['key A data R/W', 'never', 'key B', 'never', 'key A data R/W', 'key B', 'never', 'never']
index = 0
if self.C2 & 0x8 > 0:
index = 1
if self.C1 & 0x8 > 0:
index = index + 2
if self.C3 & 0x8 > 0:
index = index + 4
#print("TrailerAccess idx=",index)
print('Access key A read => never')
print('Access key A write =>', KeyAWrite[index])
print('Access key B read =>', KeyBRead[index])
print('Access key B write =>', KeyBWrite[index])
print('Access bits read =>', AccessRead[index])
print('Access bits write =>', AccessWrite[index])
def showBlockAccess(self,blockID):
BlockRead = ['key A|B','key A|B','key A|B','key A|B','key A|B','key B', 'key B', 'never' ]
BlockWrite = ['key A|B', 'never', 'key B', 'key B', 'never', 'key B','never', 'never']
BlockIncrement = ['key A|B', 'never', 'never', 'key B', 'never', 'never', 'never', 'never']
BlockDecrement = ['key A|B', 'never', 'never', 'key A|B', 'key A|B', 'never', 'never', 'never']
if blockID == 3:
self.showTrailerAccess()
else:
mask = 1 << blockID
index = 0
if (self.C2 & mask) > 0:
index =1
if (self.C1 & mask) > 0:
index = index + 2
if (self.C3 & mask) > 0:
index = index + 4
print("Block ", blockID, " read =>", BlockRead[index])
print("Block ", blockID, " write =>", BlockWrite[index])
print("Block ", blockID, " Increment =>", BlockIncrement[index])
print("Block ", blockID, " Decrement+ =>", BlockDecrement[index])
def showAccess(self):
print("/--------- SHOW ACCESS ---------\\")
AccessB = self.encodeAccess()
print('Access Bytes (6,7,8)= (',hex(AccessB[0]),', ',hex(AccessB[1]),', ',hex(AccessB[2]),')')
print('(C1, C2, C3) = (',hex(self.C1),', ',hex(self.C2),', ',hex(self.C3),')')
for i in range(4):
self.showBlockAccess(i)
print("\\---------------------------------/")
def fillBlock3(self,keyA=None,keyB=None,block=None):
if block is None:
block = 16*[0xff]
if len(block) != 16:
block = 16*[0xff]
if keyA is not None:
if len(keyA) == 6 :
block[0:6]=keyA
if keyB is not None:
if len(keyB) == 6 :
block[10:16]=keyB
b6, b7, b8 = self.encodeAccess()
block[6]=b6
block[7]=b7
block[8]=b8
return block
if __name__ == "__main__":
rfid = RfidAccess()
print("\nEx: Decode access_bits for [0xff, 0x07, 0x80]")
if rfid.decodeAccess(0xFF,0x07,0x80):
rfid.showAccess()
else:
print('Invalid Access')
print("\n\nSet block 0 to 3 to be read by KEYA but R/W with KEYB")
rfid.setBlockAccess(rfid.ALLBLOCK, access_Read=rfid.KEYAB, access_Write=rfid.KEYB, access_Inc=rfid.NEVER, access_Dec=rfid.NEVER)
print("Set sector trailer to be only set by Key B");
rfid.setTrailerAccess(keyA_Write=rfid.KEYB,access_Read=rfid.KEYAB,access_Write=rfid.KEYB,keyB_Read=rfid.NEVER,keyB_Write=rfid.KEYB)
rfid.showAccess()

View File

@@ -1,34 +0,0 @@
from mfrc522 import MFRC522
def uidToString(uid):
mystring = ""
for i in uid:
mystring = "%02X" % i + mystring
return mystring
reader = MFRC522(spi_id=0,sck=2,miso=4,mosi=3,cs=1,rst=0)
print("")
print("Place card before reader to read from address 0x08")
print("")
try:
while True:
(stat, tag_type) = reader.request(reader.REQIDL)
if stat == reader.OK:
(stat, uid) = reader.SelectTagSN()
if stat == reader.OK:
print("Card detected %s" % uidToString(uid))
else:
print("Authentication error")
except KeyboardInterrupt:
print("Bye")

View File

@@ -220,22 +220,49 @@ class MFRC522:
return 0 return 0
def SelectTag(self, uid):
byte5 = 0
#(status,puid)= self.anticoll(self.PICC_ANTICOLL1)
#print("uid",uid,"puid",puid)
for i in uid:
byte5 = byte5 ^ i
puid = uid + [byte5]
if self.PcdSelect(puid,self.PICC_ANTICOLL1) == 0:
return (self.ERR,[])
return (self.OK , uid)
def tohexstring(self,v):
s="["
for i in v:
if i != v[0]:
s = s+ ", "
s=s+ "0x{:02X}".format(i)
s= s+ "]"
return s
def SelectTagSN(self): def SelectTagSN(self):
valid_uid=[] valid_uid=[]
(status,uid)= self.anticoll(self.PICC_ANTICOLL1) (status,uid)= self.anticoll(self.PICC_ANTICOLL1)
#print("Select Tag 1:",self.tohexstring(uid))
if status != self.OK: if status != self.OK:
return (self.ERR,[]) return (self.ERR,[])
if self.DEBUG: print("anticol(1) {}".format(uid)) if self.DEBUG: print("anticol(1) {}".format(uid))
if self.PcdSelect(uid,self.PICC_ANTICOLL1) == 0: if self.PcdSelect(uid,self.PICC_ANTICOLL1) == 0:
return (self.ERR,[]) return (self.ERR,[])
if self.DEBUG: print("pcdSelect(1) {}".format(uid)) if self.DEBUG: print("pcdSelect(1) {}".format(uid))
#check if first byte is 0x88 #check if first byte is 0x88
if uid[0] == 0x88 : if uid[0] == 0x88 :
#ok we have another type of card #ok we have another type of card
valid_uid.extend(uid[1:4]) valid_uid.extend(uid[1:4])
(status,uid)=self.anticoll(self.PICC_ANTICOLL2) (status,uid)=self.anticoll(self.PICC_ANTICOLL2)
#print("Select Tag 2:",self.tohexstring(uid))
if status != self.OK: if status != self.OK:
return (self.ERR,[]) return (self.ERR,[])
if self.DEBUG: print("Anticol(2) {}".format(uid)) if self.DEBUG: print("Anticol(2) {}".format(uid))
@@ -248,6 +275,7 @@ class MFRC522:
if uid[0] == 0x88 : if uid[0] == 0x88 :
valid_uid.extend(uid[1:4]) valid_uid.extend(uid[1:4])
(status , uid) = self.anticoll(self.PICC_ANTICOLL3) (status , uid) = self.anticoll(self.PICC_ANTICOLL3)
#print("Select Tag 3:",self.tohexstring(uid))
if status != self.OK: if status != self.OK:
return (self.ERR,[]) return (self.ERR,[])
if self.DEBUG: print("Anticol(3) {}".format(uid)) if self.DEBUG: print("Anticol(3) {}".format(uid))
@@ -268,7 +296,15 @@ class MFRC522:
def auth(self, mode, addr, sect, ser): def auth(self, mode, addr, sect, ser):
return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]
def authKeys(self,uid,addr,keyA=None, keyB=None):
status = self.ERR
if keyA is not None:
status = self.auth(self.AUTHENT1A, addr, keyA, uid)
elif keyB is not None:
status = self.auth(self.AUTHENT1B, addr, keyB, uid)
return status
def stop_crypto1(self): def stop_crypto1(self):
self._cflags(0x08, 0x08) self._cflags(0x08, 0x08)
@@ -278,7 +314,7 @@ class MFRC522:
data = [0x30, addr] data = [0x30, addr]
data += self._crc(data) data += self._crc(data)
(stat, recv, _) = self._tocard(0x0C, data) (stat, recv, _) = self._tocard(0x0C, data)
return recv if stat == self.OK else None return stat, recv
def write(self, addr, data): def write(self, addr, data):
@@ -296,22 +332,53 @@ class MFRC522:
(stat, recv, bits) = self._tocard(0x0C, buf) (stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR stat = self.ERR
return stat return stat
def MFRC522_DumpClassic1K(self, key, uid, Start=0, End=64):
for i in range(Start,End): def writeSectorBlock(self,uid, sector, block, data, keyA=None, keyB = None):
status = self.auth(self.AUTHENT1A, i, key, uid) absoluteBlock = sector * 4 + (block % 4)
if absoluteBlock > 63 :
return self.ERR
if len(data) != 16:
return self.ERR
if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR :
return self.write(absoluteBlock, data)
return self.ERR
def readSectorBlock(self,uid ,sector, block, data,keyA=None, keyB = None):
absoluteBlock = sector * 4 + (block % 4)
if page > 63 :
return self.ERR, None
if len(data) != 16:
return self.ERR, None
if self.authKeys(uid,page,KeyA,KeyB) != self.ERR :
return self.read(page)
return self.ERR, None
def MFRC522_DumpClassic1K(self,uid, Start=0, End=64, keyA=None, keyB=None):
for absoluteBlock in range(Start,End):
status = self.authKeys(uid,absoluteBlock,keyA,keyB)
# Check if authenticated # Check if authenticated
print("{:02d}: ".format(i),end="") print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock, absoluteBlock//4 , absoluteBlock % 4),end="")
if status == self.OK: if status == self.OK:
block = self.read(i) status, block = self.read(absoluteBlock)
if block is None: if status == self.ERR:
print("-- ") break
else: else:
for value in block: for value in block:
print("{:02X} ".format(value),end="") print("{:02X} ".format(value),end="")
print(" ",end="")
for value in block:
if (value > 0x20) and (value < 0x7f):
print(chr(value),end="")
else:
print('.',end="")
print("") print("")
else: else:
print("Authentication error") break
if status == self.ERR:
print("Authentication error")
return self.ERR
return self.OK