diff --git a/Pico_example/CreateNdefTag.py b/Pico_example/CreateNdefTag.py new file mode 100644 index 0000000..a6afd11 --- /dev/null +++ b/Pico_example/CreateNdefTag.py @@ -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") + + + diff --git a/Pico_example/EraseNdefTag.py b/Pico_example/EraseNdefTag.py new file mode 100644 index 0000000..e47ddf1 --- /dev/null +++ b/Pico_example/EraseNdefTag.py @@ -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!") + + diff --git a/Pico_example/Pico_read.py b/Pico_example/Pico_read.py new file mode 100644 index 0000000..8950f52 --- /dev/null +++ b/Pico_example/Pico_read.py @@ -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 \ No newline at end of file diff --git a/examples/Pico_write.py b/Pico_example/Pico_write.py similarity index 86% rename from examples/Pico_write.py rename to Pico_example/Pico_write.py index cb1542e..6cc04cd 100644 --- a/examples/Pico_write.py +++ b/Pico_example/Pico_write.py @@ -17,7 +17,7 @@ def uidToString(uid): 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("Please place card on reader") print("") key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF] @@ -32,7 +32,7 @@ try: if stat == reader.OK: print(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("with [ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 ]") absoluteBlock=8 @@ -43,7 +43,7 @@ try: if status == reader.OK: status = reader.write(absoluteBlock,value) if status == reader.OK: - reader.MFRC522_DumpClassic1K(key, uid) + reader.MFRC522_DumpClassic1K(uid,keyA=key) else: print("unable to write") else: diff --git a/Pico_example/ReadNdefTag.py b/Pico_example/ReadNdefTag.py new file mode 100644 index 0000000..860e2c8 --- /dev/null +++ b/Pico_example/ReadNdefTag.py @@ -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") + + + diff --git a/RfidAccess.py b/RfidAccess.py new file mode 100644 index 0000000..89b6fbe --- /dev/null +++ b/RfidAccess.py @@ -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() + + + diff --git a/examples/Pico_read.py b/examples/Pico_read.py deleted file mode 100644 index 541c8b3..0000000 --- a/examples/Pico_read.py +++ /dev/null @@ -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") - - diff --git a/mfrc522.py b/mfrc522.py index f73aec6..e12ae77 100644 --- a/mfrc522.py +++ b/mfrc522.py @@ -220,22 +220,49 @@ class MFRC522: 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): valid_uid=[] (status,uid)= self.anticoll(self.PICC_ANTICOLL1) + #print("Select Tag 1:",self.tohexstring(uid)) if status != self.OK: return (self.ERR,[]) - + if self.DEBUG: print("anticol(1) {}".format(uid)) if self.PcdSelect(uid,self.PICC_ANTICOLL1) == 0: return (self.ERR,[]) if self.DEBUG: print("pcdSelect(1) {}".format(uid)) - + #check if first byte is 0x88 if uid[0] == 0x88 : #ok we have another type of card valid_uid.extend(uid[1:4]) (status,uid)=self.anticoll(self.PICC_ANTICOLL2) + #print("Select Tag 2:",self.tohexstring(uid)) if status != self.OK: return (self.ERR,[]) if self.DEBUG: print("Anticol(2) {}".format(uid)) @@ -248,6 +275,7 @@ class MFRC522: if uid[0] == 0x88 : valid_uid.extend(uid[1:4]) (status , uid) = self.anticoll(self.PICC_ANTICOLL3) + #print("Select Tag 3:",self.tohexstring(uid)) if status != self.OK: return (self.ERR,[]) if self.DEBUG: print("Anticol(3) {}".format(uid)) @@ -268,7 +296,15 @@ class MFRC522: def auth(self, mode, addr, sect, ser): 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): self._cflags(0x08, 0x08) @@ -278,7 +314,7 @@ class MFRC522: data = [0x30, addr] data += self._crc(data) (stat, recv, _) = self._tocard(0x0C, data) - return recv if stat == self.OK else None + return stat, recv def write(self, addr, data): @@ -296,22 +332,53 @@ class MFRC522: (stat, recv, bits) = self._tocard(0x0C, buf) if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): stat = self.ERR - return stat - def MFRC522_DumpClassic1K(self, key, uid, Start=0, End=64): - for i in range(Start,End): - status = self.auth(self.AUTHENT1A, i, key, uid) + + def writeSectorBlock(self,uid, sector, block, data, keyA=None, keyB = None): + 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 - print("{:02d}: ".format(i),end="") + print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock, absoluteBlock//4 , absoluteBlock % 4),end="") if status == self.OK: - block = self.read(i) - if block is None: - print("-- ") + status, block = self.read(absoluteBlock) + if status == self.ERR: + break else: for value in block: 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("") else: - print("Authentication error") - + break + if status == self.ERR: + print("Authentication error") + return self.ERR + return self.OK + +