How to Calculate MIFARE Access Bits — Sector Trailer Permissions Guide
MIFARE Classic 1K and 4K cards use a clever but confusing 3-bit access encoding (C1, C2, C3) stored in the sector trailer. Each sector's last block (block 3 for 1K, block 15 for 4K) contains Key A (6 bytes) + Access Bits (4 bytes) + Key B (6 bytes). The access bits define exactly which key is needed to read, write, increment, decrement, transfer, and restore each data block.
1. Sector Trailer Layout (Block 3)
Bytes 0-5: Key A (6 bytes) — default: 0xFF FF FF FF FF FF Bytes 6-9: Access Bits (4 bytes) — controls all 4 blocks of sector Bytes 10-15: Key B (6 bytes) — default: 0xFF FF FF FF FF FF # Transport configuration (factory default): # Key A = FFFFFFFFFFFF, Key B = FFFFFFFFFFFF # Access Bits = FF 07 80 69 # → All blocks: Key A or Key B can read/write, transport mode
2. What C1/C2/C3 Control for Each Block
Each data block (0, 1, 2) has its own C1/C2/C3 triplet. The sector trailer (block 3) has a separate triplet that controls access to Key A, Key B, and the access bits themselves:
| Block | Access Bits Control |
|---|---|
| Data Block 0 | Read, Write, Increment, Decrement/Transfer/Restore permissions |
| Data Block 1 | Same operations as above |
| Data Block 2 | Same operations as above (or value block operations) |
| Block 3 (Trailer) | Access to Key A read/write, Key B read/write, access bits read/write |
3. How Access Bits Are Stored in Bytes 6-9
This is the tricky part. The 4 access bytes store C1/C2/C3 for all 4 blocks, but they are stored in inverted+non-inverted pairs and interleaved across bytes:
Byte 6: ~C23 ~C22 ~C21 ~C20 ~C13 ~C12 ~C11 ~C10 Byte 7: ~C13 ~C12 ~C11 ~C10 ~C33 ~C32 ~C31 ~C30 Byte 8: C33 C32 C31 C30 C23 C22 C21 C20 Byte 9: C13 C12 C11 C10 C33 C32 C31 C30 # Notation: # C13 = C1 for block 3 (trailer) ~C13 = inverted C1 for block 3 # C10 = C1 for block 0 (data) ~C10 = inverted C1 for block 0 # The ~ prefix means BITWISE NOT (inverted) # Storing both normal and inverted provides error detection
4. Access Condition Rules
| C1 C2 C3 | Read | Write | Increment | Dec/Trans/Rest |
|---|---|---|---|---|
| 0 0 0 | Key A|B | Key A|B | Key A|B | Key A|B |
| 0 1 0 | Key A|B | Never | Never | Never |
| 1 0 0 | Key A|B | Key B | Never | Never |
| 1 1 0 | Key A|B | Key B | Key A|B | Key A|B |
| 0 0 1 | Key A|B | Never | Never | Key A|B |
| 0 1 1 | Key B | Key B | Never | Never |
| 1 0 1 | Key B | Never | Never | Never |
| 1 1 1 | Never | Never | Never | Never |
5. Sector Trailer Access Bits (Block 3)
The trailer block has its own access rules controlling key access:
| C1 C2 C3 | Key A Read | Key A Write | Access Bits Read | Access Bits Write | Key B Read | Key B Write |
|---|---|---|---|---|---|---|
| 0 0 0 | Never | Key A | Key A | Never | Key A | Key A |
| 0 0 1 | Never | Never | Key A | Never | Key A | Never |
| 0 1 1 | Never | Key B | Key A|B | Never | Never | Key B |
| 1 0 0 | Never | Never | Key A|B | Never | Never | Never |
| 1 1 0 | Never | Key B | Key A|B | Key B | Never | Never |
| 1 1 1 | Never | Never | Key A|B | Never | Never | Never |
Critical note: Key A can never be read (last 6 bytes of trailer return zeros). Setting access bits that deny Key A write locks you out of the sector permanently.
6. Python Calculator
def encode_access_bits(c1c2c3_blocks):
"""Encode 4 blocks of C1/C2/C3 triplets into access bytes 6-9.
c1c2c3_blocks: list of 4 tuples [(c1,c2,c3)_b0, ..., (c1,c2,c3)_b3]
"""
# Extract C1, C2, C3 for each block
c1 = [b[0] for b in c1c2c3_blocks] # [c1_b0, c1_b1, c1_b2, c1_b3]
c2 = [b[1] for b in c1c2c3_blocks]
c3 = [b[2] for b in c1c2c3_blocks]
# Pack bits (C2 in upper nibble, C1 in lower nibble for each byte pair)
def pack_4bits(bits): # bits = [b0, b1, b2, b3]
return (bits[3] << 3) | (bits[2] << 2) | (bits[1] << 1) | bits[0]
byte6 = (~pack_4bits(c2) & 0x0F) << 4 | (~pack_4bits(c1) & 0x0F)
byte7 = (~pack_4bits(c1) & 0x0F) << 4 | (~pack_4bits(c3) & 0x0F)
byte8 = pack_4bits(c3) << 4 | pack_4bits(c2)
byte9 = pack_4bits(c1) << 4 | pack_4bits(c3)
return bytes([byte6, byte7, byte8, byte9])
# Example: Transport config (all blocks C1=0,C2=0,C3=0)
print(encode_access_bits([(0,0,0)]*4).hex().upper()) # → FF078069
7. Common Access Bit Configurations
# Read-only data block, Key A|B for read, no write (C=010): # Bytes 6-9: 0F 00 FF FF (only block 0 read-only, others transport) # Value block with Key B for increment/decrement (C=110): # C1=1, C2=1, C3=0 → Key A|B read, Key B write/inc/dec # Fully locked card (all blocks C=111, trailer C=001): # Everything is read-only, even trailer locked
Related Tools
MIFARE Access Bits Calculator — Interactive access bits editor | MIFARE Classic vs DESFire — Security comparison | NFC Capacity Calculator — Check sector usage