def read_block(self, block, noauth=False): '''Works only for data blocks, whereas for the trailer blocks reads the ACL only''' if not noauth: self.auth(block, READ) data = mifare.read(self.reader, block) sector = self.block2sector(block) tblock = self.trailer_block(sector) if block == tblock: data = self.fix_trailer_block(sector, data) return data
def auth(self, block, access_type): '''Authentication needs to be done once per sector. After successful authentication any number of blocks from the sector can be read/written to.''' # find out the sector we are going to access sector = self.block2sector(block) # only do the authentication if we have required keys loaded if sector >= len(self._keys): raise RuntimeError( 'Cannot unlock sector %d - no key for the sector provided!' % (sector)) # check the access conditions for this data block tblock = self.trailer_block(sector) auth_key = 0 if sector in self._trailer_cache: tdata = self._trailer_cache[sector] else: # we have read the trailer block, se have to authenticate to the sector anyway if mifare.auth(self.reader, block, mifare.MC_AUTH_A, self._keys[sector]['a'], self.uid()): auth_key = 1 elif mifare.auth(self.reader, block, mifare.MC_AUTH_B, self._keys[sector]['b'], self.uid()): auth_key = 2 else: raise RuntimeError('Cannot unlock sector %d' % (sector)) tdata = self._trailer_cache[sector] = mifare.read( self.reader, tblock) keya, access_cond, keyb = struct.unpack('6s4s6s', tdata) access_cond = self._parse_acl(access_cond) sblock = block % self.sector_size(sector) # read or write access condition, see data_acl for data blocks and trailer_acl for the trailer block auth_keys = access_cond[sblock][ access_type] if block != tblock else access_cond[sblock]['acl'][ access_type] if auth_keys == 0: raise RuntimeError("ACL denies %s on sector %d, block %d" % (['reads', 'writes'][access_type], sector, i)) if not auth_keys & auth_key: keytype = mifare.MC_AUTH_B if auth_keys == 2 else mifare.MC_AUTH_A keyidx = 'a' if keytype == mifare.MC_AUTH_A else 'b' if not mifare.auth(self.reader, block, keytype, self._keys[sector][keyidx], self.uid()): raise RuntimeError( 'Authentication of sector %d, block %d failed' % (sector, i)) return True
def auth(self, block, access_type): '''Authentication needs to be done once per sector. After successful authentication any number of blocks from the sector can be read/written to.''' # find out the sector we are going to access sector = self.block2sector(block) # only do the authentication if we have required keys loaded if sector >= len(self._keys): raise RuntimeError('Cannot unlock sector %d - no key for the sector provided!' % (sector)) # check the access conditions for this data block tblock = self.trailer_block(sector) auth_key = 0 if sector in self._trailer_cache: tdata = self._trailer_cache[sector] else: # we have read the trailer block, se have to authenticate to the sector anyway if mifare.auth(self.reader, block, mifare.MC_AUTH_A, self._keys[sector]['a'], self.uid()): auth_key = 1 elif mifare.auth(self.reader, block, mifare.MC_AUTH_B, self._keys[sector]['b'], self.uid()): auth_key = 2 else: raise RuntimeError('Cannot unlock sector %d' % (sector)) tdata = self._trailer_cache[sector] = mifare.read(self.reader, tblock) keya, access_cond, keyb = struct.unpack('6s4s6s', tdata) access_cond = self._parse_acl(access_cond) sblock = block % self.sector_size(sector) # read or write access condition, see data_acl for data blocks and trailer_acl for the trailer block auth_keys = access_cond[sblock][access_type] if block != tblock else access_cond[sblock]['acl'][access_type] if auth_keys == 0: raise RuntimeError("ACL denies %s on sector %d, block %d" % (['reads','writes'][access_type], sector, i)) if not auth_keys & auth_key: keytype = mifare.MC_AUTH_B if auth_keys == 2 else mifare.MC_AUTH_A keyidx = 'a' if keytype == mifare.MC_AUTH_A else 'b' if not mifare.auth(self.reader, block, keytype, self._keys[sector][keyidx], self.uid()): raise RuntimeError('Authentication of sector %d, block %d failed' % (sector, i)) return True